Related
I am trying to write code to test the speed of lz4 compression instead of using -b code in terminal.
I am using ubuntu Ubuntu 20.04.2 LTS. And visual studio ide.
Here is my code, it has some trouble when running the second time of the for loop in main.
This line:
fread(src,16384,1,fc);
When i = 1, it works as I expected. However, when i = 2, the malloc() problem just pop up.
//The split file function works perfectly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lz4.h"
int splitFile(char* fileIn, size_t maxSize);
#include "lz4.c"
int main()
{
time_t start,end;
int compress, decompress;
int64_t num_f=0;
int64_t i;
char* src=malloc(16384);
int srcSize= 16385;//(int)(strlen(src) + 1);
int dstCapacity=0;
int compressed_data_size=0;
char* compressed_data = malloc((size_t)dstCapacity);
char buff[200];
FILE * fc;
num_f = splitFile("/home/ziruo/research/1stpro/test.txt",16384);
printf("num_f=%ld\n",num_f);
start = time(NULL);
for( i = 1; i <= num_f; i++)
{
sprintf(buff,"/home/ziruo/research/1stpro/test.txt.%03d",i);
printf("buff %s\n",&buff);
if (compressed_data == NULL)
{
printf("faild to generae storage\n");
}
fc = fopen(buff,"r");
printf("fc is: %d\n",fc);
fread(src,16384,1,fc);
srcSize=(int)(strlen(src) + 1);
dstCapacity= LZ4_compressBound(srcSize)
compressed_data_size = LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
LZ4_compress_default(src,compressed_data,srcSize,dstCapacity);
printf("data size ratio %.2f\n", (float)compressed_data_size/srcSize);
}
end = time(NULL);
printf("time used(s): %f\n",difftime(end,start));
return 0;
}
int splitFile(char* fileIn, size_t maxSize)
{
int result = 0;
FILE* fIn;
FILE* fOut;
char buffer[1024 * 16];
size_t size;
size_t read;
size_t written;
if ((fileIn != NULL) && (maxSize > 0))
{
fIn = fopen(fileIn, "rb");
if (fIn != NULL)
{
fOut = NULL;
result = 1; // we have at least one part
while (!feof(fIn))
{
// initialize (next) output file if no output file opened
if (fOut == NULL)
{
sprintf(buffer, "%s.%03d", fileIn, result);
fOut = fopen(buffer, "wb");
if (fOut == NULL)
{
result = -1;
break;
}
size = 0;
}
// calculate size of data to be read from input file in order to not exceed maxSize
read = sizeof(buffer);
if ((size + read) > maxSize)
{
read = maxSize - size;
}
// read data from input file
read = fread(buffer, 1, read, fIn);
if (read == 0)
{
result = -1;
break;
}
// write data to output file
written = fwrite(buffer, 1, read, fOut);
if (written != read)
{
result = -1;
break;
}
// update size counter of current output file
size += written;
if (size >= maxSize) // next split?
{
fclose(fOut);
fOut = NULL;
result++;
}
}
// clean up
if (fOut != NULL)
{
fclose(fOut);
}
fclose(fIn);
}
}
return (result);
}
And here is the picture of error
enter image description here
I'm currently implementing a function to use the "external sort" method because I have to sort a big file (+200K lines) on a device with low RAM, right now just trying to make it run on a windows pc.
I'm working on the function to split the file in tiny sorted files.
The problem I'm facing is that among the tiny sorted files the function creates, the data on certain lines are truncated.
I'm quite sure I've done a mistake somewhere but was not able to find it, yet. Could you help me to discover the problem please ?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LEN 50
#define MAX_LINES_SORTED 130
void createSortedFiles(FILE*);
int main()
{
FILE *fp = fopen("C:\\C\\Tests\\1.txt", "r+");
if(fp == NULL){
printf("Error opening fp");
return 1;
}
createSortedFiles(fp);
fclose(fp);
return 0;
}
int cmp(const void *p1, const void *p2) {
return strcmp(p1, p2);
}
void createSortedFiles(FILE* fp) {
FILE* sfp;
//FILE* sfp2 = fopen("C:\\C\\Tests\\test.txt", "w+");
char lines[MAX_LINES_SORTED][MAX_LINE_LEN + 1] = {0}, buffer[MAX_LINE_LEN + 1] = { 0 }, fnum[6];
char fname[20] = "C:\\C\\Tests\\";
char *p;
int i = 0, j = 0 /*file names*/, int max_lines = MAX_LINES_SORTED - 1;
size_t N;
while (1){
p = fgets(buffer, MAX_LINE_LEN, fp);
// fwrite(buffer, strlen(buffer), 1, sfp2);
if(strlen(buffer) > 0 || i > 0){
if(p != NULL)
memcpy(lines[i], buffer, strlen(buffer));
//If reached the max number of lines accepted in the array
//Or reached EOF
//=> Sort and write the array "lines"
if (i >= max_lines || p == NULL) {
N = sizeof(lines) / sizeof(lines[0]);
qsort(lines, N, sizeof(*lines), cmp);
//sets the name of the current file
memset(&fname[11], 0, 9);
itoa(j, fnum, 10);
strcat(fname, fnum);
if ((sfp = fopen(fname, "w+")) == NULL) {
printf("Error opening sfp");
return;
}
for (i = 0; i < N; i++) {
fwrite(lines[i], strlen(lines[i]), 1, sfp);
}
fclose(sfp);
memset(lines, 0, sizeof(lines[0][0]) * MAX_LINES_SORTED * MAX_LINE_LEN);
j++; i = -1; //because incremented right after
}
}
if(p == NULL){
break;
}
i++;
}
//fclose(sfp2);
return;
}
Here's an example of the fp file (each lines ending with \r\n):
8023796280724;00060-014.W47
8023796280731;00060-014.W48
;0009070305/08007
;0009470337/08007
;0009490338/13001
;0010480311/08007
;0010830308/08007
;0011S
8033280129293;002004GRS4XL
;002015RSM
5708628117005;00207-630-06T42
5708628117012;00207-630-06T44
5708628117036;00207-630-06T46
4051428088756;647530241000045
4051428088763;647530241000046
4051428088770;647530241000047
;647BLPMF
4051428092586;648510256000040
4051428092593;648510256000041
4051428092609;648510256000042
4051428092616;648510256000043
4051428092623;648510256000044
4051428092630;648510256000045
4051428092647;648510256000046
Your "truncated lines" are not really truncated lines, they are stray data left in the buffer from previous files.
This array:
#define MAX_LINE_LEN 50
#define MAX_LINES_SORTED 130
char lines[MAX_LINES_SORTED][MAX_LINE_LEN + 1];
has 6630 bytes, but here:
memset(lines, 0, sizeof(lines[0][0]) * MAX_LINES_SORTED * MAX_LINE_LEN);
you zero out only 6500 bytes and leave the last two lines as they are.
You can fix this by using (MAX_LINE_LEN +1) in the size calculation, but the array can be zeroes out more tersely (and more reliably) with just:
memset(lines, 0, sizeof(lines));
I am trying to copy binary files from src to dst. This script seems to copy all of the bytes. BUT when I open both files in Hex Workshop I see that dst file is always missing 3 bytes at the end of the file. These 3 bytes should have been 00 00 00, this problem prevents me from opening dst file.
void binaryCopy(char **argv) {
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(argv[SRC_POS], "rb");
FILE *dst = fopen(argv[DST_POS], "w+b");
if (src) {
if (dst) {
wantOverwrite = overwrite();
}
if (wantOverwrite) {
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
buf = (int *)malloc(size);
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
printf("copy completed");
free(buf);
}
}
fclose(dst);
fclose(src);
}
There are several problems in your function as written.
fopen(dstFilename, "w+b"); truncates the file, so your overwrite check later is meaningless.
You're not checking for NULL after malloc, and your buffer should be an unsigned char* since that is what fread/fwrite will interpret it as.
At the end, both fclose functions could be called with NULL file pointers likely resulting in a crash. You should move them into the scopes where you know each was successfully opened.
The big problem, the one that prompted this question, is that you are not handling cases where the size of the file is not an even multiple of whatever BYTE_SIZE is. Since you allocated enough memory for the whole file you should just read and write the whole file. fread(buf, 1, size, src); and fwrite(buf, 1, size, dst);. In general it is best to make the element size parameter of fread/fwrite 1 and the count the number of bytes you want to read or write. There's no math to go wrong, and you can tell exactly how many bytes were read/written.
Here's a version of your original function that I've corrected and annotated so it works if nothing goes wrong.
void originalBinaryCopy(const char *srcFilename, const char *dstFilename)
{
//odd size to ensure remainder
const size_t BYTE_SIZE = 777;
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(srcFilename, "rb");
//This truncates dst, so the overwirte check is meaningless
FILE *dst = fopen(dstFilename, "w+b");
if (src)
{
if (dst)
{
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
//always check for NULL after malloc - This should be a char*
buf = (int *)malloc(size);
if (!buf)
{
fclose(dst);
fclose(src);
return;
}
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
//added, copy remainder
elements = fread(buf, 1, size % BYTE_SIZE, src);
fwrite(buf, 1, size % BYTE_SIZE, dst);
//end
printf("copy completed %s -> %s\n", srcFilename, dstFilename);
free(buf);
}
}
//dst could be NULL here, move inside if(dst) scope above
fclose(dst);
//src could be NULL here, move inside if(src) scope above
fclose(src);
if (comp(srcFilename, dstFilename) != 0)
{
printf("compare failed - %s -> %s\n", srcFilename, dstFilename);
}
}
Notice how the remainder is handled at the end.
Here is how I would handle copying files along with a test suite to create, copy, and verify a set of files. It shows how to avoid truncating the destination if you don't want to and has quite a bit of error checking in the actual functions. I did not include any specific error checking on the caller side, but for real code I would have enumerated all of the possible errors and used those return values to pass to an error handling function that could print them out and possibly exit the program.
Manipulating files is one thing you want to be VERY careful about since there's potential for data loss if your code doesn't work, so before you use it with real files make sure it's 100% solid with test files.
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TEST_FILE_MIN 1024
#define TEST_FILE_MAX 1024 * 1024
const char *src_pattern = "src_file_%08x.bin";
const char *dst_pattern = "dst_file_%08x.bin";
void createTestFiles(const char *pattern)
{
char filename[256] = { 0 };
char buffer[1024];
for (size_t i = 0; i < sizeof(buffer); ++i)
{
buffer[i] = rand();
}
for (size_t i = TEST_FILE_MIN; i <= TEST_FILE_MAX; i *= 2)
{
sprintf(filename, pattern, i);
FILE *dst = fopen(filename, "wb");
if (dst)
{
size_t reps = i / TEST_FILE_MIN;
for (size_t w = 0; w < reps; ++w)
{
fwrite(buffer, 1, sizeof(buffer), dst);
}
fclose(dst);
}
}
}
int comp(const char *srcFilename, const char *dstFilename)
{
FILE *src = fopen(srcFilename, "rb");
if (!src)
{
return -1;
}
//open for reading to check for existence
FILE *dst = fopen(dstFilename, "rb");
if (!dst)
{
fclose(src);
return -2;
}
fseek(src, 0, SEEK_END);
size_t srcSize = ftell(src);
fseek(src, 0, SEEK_SET);
fseek(dst, 0, SEEK_END);
size_t dstSize = ftell(dst);
fseek(dst, 0, SEEK_SET);
if (srcSize == 0 || dstSize == 0 || srcSize != dstSize)
{
fclose(src);
fclose(dst);
return -3;
}
unsigned char *srcBuf = (unsigned char *)calloc(1, srcSize);
unsigned char *dstBuf = (unsigned char *)calloc(1, srcSize);
if (!srcBuf || !dstBuf)
{
fclose(src);
fclose(dst);
return -4;
}
if (fread(srcBuf, 1, srcSize, src) != srcSize)
{
fclose(src);
fclose(dst);
return -5;
}
if (fread(dstBuf, 1, dstSize, dst) != dstSize)
{
fclose(src);
fclose(dst);
return -6;
}
fclose(src);
fclose(dst);
//result * 100 to make this error outside te range of the other general errors from this function.
int result = memcmp(srcBuf, dstBuf, srcSize) * 100;
free(srcBuf);
free(dstBuf);
return result;
}
void originalBinaryCopy(const char *srcFilename, const char *dstFilename)
{
//odd size to ensure remainder
const size_t BYTE_SIZE = 777;
int *buf = 0;
int elements = 0;
int size = 0, wantOverwrite = 0;
FILE *src = fopen(srcFilename, "rb");
//This truncates dst, so the overwirte check is meaningless
FILE *dst = fopen(dstFilename, "w+b");
if (src)
{
if (dst)
{
fseek(src, 0L, SEEK_END);
size = ftell(src);
fseek(src, 0L, SEEK_SET);
//always check for NULL after malloc - This should be a char*
buf = (int *)malloc(size);
if (!buf)
{
fclose(dst);
fclose(src);
return;
}
elements = fread(buf, BYTE_SIZE, size / BYTE_SIZE, src);
fwrite(buf, BYTE_SIZE, elements, dst);
//added, copy remainder
elements = fread(buf, 1, size % BYTE_SIZE, src);
fwrite(buf, 1, size % BYTE_SIZE, dst);
//end
printf("copy completed %s -> %s\n", srcFilename, dstFilename);
free(buf);
}
}
//dst could be NULL here, move inside if(dst) scope above
fclose(dst);
//src could be NULL here, move inside if(src) scope above
fclose(src);
if (comp(srcFilename, dstFilename) != 0)
{
printf("compare failed - %s -> %s\n", srcFilename, dstFilename);
}
}
int binaryCopy(const char *srcFilename, const char *dstFilename, bool overwrite)
{
//arbitrary odd size so we can make sure we handle a partial buffer.
//assuming the code tests successfully I'd use something like 64 * 1024.
unsigned char buffer[7777] = { 0 };
FILE *src = fopen(srcFilename, "rb");
if (!src)
{
//Error, source file could not be opened
return -1;
}
//open for reading to check for existence
FILE *dst = fopen(dstFilename, "rb");
if (dst)
{
if (!overwrite)
{
//Error, dest file exists and we can't overwrite it
fclose(src);
fclose(dst);
return -2;
}
//reopen dst it for writing
if (!freopen(dstFilename, "wb", dst))
{
fclose(src);
fclose(dst);
dst = NULL;
}
}
else
{
//it didn't exist, create it.
dst = fopen(dstFilename, "wb");
}
if (!dst)
{
//Error, dest file couldn't be opened
fclose(src);
return -3;
}
//Get the size of the source file for comparison with what we read and write.
fseek(src, 0, SEEK_END);
size_t srcSize = ftell(src);
fseek(src, 0, SEEK_SET);
size_t totalRead = 0;
size_t totalWritten = 0;
size_t bytesRead = 0;
while (bytesRead = fread(buffer, 1, sizeof(buffer), src))
{
totalRead += bytesRead;
totalWritten += fwrite(buffer, 1, bytesRead, dst);
}
fclose(dst);
fclose(src);
if (totalRead != srcSize)
{
//src read error
return -4;
}
if (totalWritten != srcSize)
{
//dst write error
return -5;
}
return 0;
}
int main()
{
srand((unsigned)time(0));
createTestFiles(src_pattern);
for (size_t i = TEST_FILE_MIN; i <= TEST_FILE_MAX; i *= 2)
{
char srcName[256];
char dstName[256];
sprintf(srcName, src_pattern, i);
sprintf(dstName, dst_pattern, i);
//use my copy to create dest file
if (binaryCopy(srcName, dstName, true) != 0)
{
printf("File: '%s' failed initial copy.", srcName);
}
originalBinaryCopy(srcName, dstName);
if (binaryCopy(srcName, dstName, true) != 0)
{
printf("File: '%s' failed overwrite copy.", srcName);
}
if (binaryCopy(srcName, dstName, false) == 0)
{
printf("File: '%s' succeeded when file exists and overwrite was not set.", srcName);
}
//If compare succeeds delete the files, otherwise leave them for external comparison and print an error.
if (comp(srcName, dstName) == 0)
{
if (remove(srcName) != 0)
{
perror("Could not remove src.");
}
if (remove(dstName) != 0)
{
perror("Could not remove dst.");
}
}
else
{
printf("File: '%s' did not compare equal to '%s'.", srcName, dstName);
}
}
return 0;
}
Hopefully this gives you something to experiment with to make sure your copier is as good as it can be. Also worth noting, I would not distinguish copying text/binary files. Files are files and if your goal is to copy them then you should always do it in binary mode so the copy is identical. On operating systems other than Windows it wouldn't matter, but on Windows there are a number of pitfalls you can run into in text mode. Best to avoid those completely if you can.
Good luck!
The most probable cause for your observation is the file size is not a multiple of BYTE_SIZE: fread(buf, BYTE_SIZE, size / BYTE_SIZE , src); reads a multiple of BYTE_SIZE and the fwrite call writes the bytes read.
If BYTE_SIZE is 4, as the type int* buf = 0; seems to indicate, and if the source file has 3 more bytes than a multiple of 4, your observations would be fully explained.
You can correct the problem by making buf an unsigned char * and changing the code to:
elements = fread(buf, 1, size , src);
fwrite(buf, 1, elements, dst);
Note also that there is no need to open the files in update mode (the + in the mode string), errors and not handled explicitly and the fclose() calls are misplaced.
Also it seems incorrect to truncate the destination file if overwrite() returns 0.
Here is a corrected version with better error handling:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int binaryCopy(char *argv[]) {
FILE *src, *dst;
long file_size;
size_t size, size_read, size_written;
int wantOverwrite;
unsigned char *buf;
if ((src = fopen(argv[SRC_POS], "rb")) == NULL) {
printf("cannot open input file %s: %s\n", argv[SRC_POS], strerror(errno));
return -1;
}
wantOverwrite = overwrite();
if (!wantOverwrite) {
fclose(src);
return 0;
}
if ((dst = fopen(argv[DST_POS], "wb")) == NULL) {
printf("cannot open output file %s: %s\n", argv[DST_POS], strerror(errno));
fclose(src);
return -1;
}
fseek(src, 0L, SEEK_END);
file_size = ftell(src);
fseek(src, 0L, SEEK_SET);
size = (size_t)file_size;
if ((long)size != file_size) {
printf("file size too large for a single block: %ld\n", file_size);
fclose(src);
fclose(dst);
return -1;
}
buf = malloc(size);
if (buf == NULL) {
printf("cannot allocate block of %zu bytes\n", size);
fclose(src);
fclose(dst);
return -1;
}
size_read = fread(buf, 1, size, src);
if (size_read != size) {
printf("read error: %zu bytes read out of %zu\n", size_read, size);
}
size_written = fwrite(buf, 1, size_read, dst);
if (size_written != size_read) {
printf("write error: %zu bytes written out of %zu\n", size_written, size_read);
}
if (size_written == size) {
printf("copy completed\n");
}
free(buf);
fclose(dst);
fclose(src);
return 0;
}
i want to print the values in the location not the address..
when i run the program using breakpoint it does increases the values but doesn't print the values contained in the addresses..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "conio.h"
int main()
{
char ch;
char buffer[100];
char* p;
p = buffer;
FILE *fp;
fp = fopen("D:\\Telenor_Short_01.vts","rb");// binary mode
fseek(fp,0,SEEK_END); //sets the file position of the stream to the given offset
int size=ftell(fp); //returns the current file position of the given stream.
printf("size of file is :%d\n",size);
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
fread(p,1,100,fp);
for (int i=0;i<100;i++)
{
printf("%04x\n",*p);
p++;
}
fclose(fp);
/*printf("The contents of %s file are :\n", file_name);*/
/*int i;
while( ( ch = fgetc(fp) ) != EOF )
{
printf("%02X ",ch);
if( !(++i % 16) ) putc('\n', stdout);
}
fclose(fp);
putc('\n', stdout);*/
_getch();
return 0;
}
this is the output:
size of file is :185153907
5bf894
5bf895
5bf896
5bf897
5bf898
5bf899
5bf89a
5bf89b
5bf89c
5bf89d
5bf89e
5bf89f
5bf8a0
5bf8a1
5bf8a2
5bf8a3
5bf8a4
5bf8a5
5bf8a6
5bf8a7
5bf8a8
5bf8a9
5bf8aa
5bf8ab
5bf8ac
5bf8ad
5bf8ae
5bf8af
5bf8b0
5bf8b1
5bf8b2
5bf8b3
5bf8b4
5bf8b5
5bf8b6
5bf8b7
5bf8b8
5bf8b9
5bf8ba
5bf8bb
5bf8bc
5bf8bd
5bf8be
5bf8bf
5bf8c0
5bf8c1
5bf8c2
5bf8c3
5bf8c4
5bf8c5
5bf8c6
5bf8c7
5bf8c8
5bf8c9
5bf8ca
5bf8cb
5bf8cc
5bf8cd
5bf8ce
5bf8cf
5bf8d0
5bf8d1
5bf8d2
5bf8d3
5bf8d4
5bf8d5
5bf8d6
5bf8d7
5bf8d8
5bf8d9
5bf8da
5bf8db
5bf8dc
5bf8dd
5bf8de
5bf8df
5bf8e0
5bf8e1
5bf8e2
5bf8e3
5bf8e4
5bf8e5
5bf8e6
5bf8e7
5bf8e8
5bf8e9
5bf8ea
5bf8eb
5bf8ec
5bf8ed
5bf8ee
5bf8ef
5bf8f0
5bf8f1
5bf8f2
5bf8f3
5bf8f4
5bf8f5
5bf8f6
5bf8f7
but i want the values ..
First, check fp for NULL immediately after fopen. Second seek to the beginning of the file before fread. Last, most importantly, check the return value of fread, because that's the number of elements that was read into the buffer. It may be smaller than the buffer.
fp = fopen("D:\\Telenor_Short_01.vts","rb");// binary mode
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
fseek(fp,0,SEEK_END); //sets the file position of the stream to the given offset
int size=ftell(fp); //returns the current file position of the given stream.
printf("size of file is :%d\n",size);
fseek(fp, 0, SEEK_SET);
int nread = fread(p, 1, 100, fp);
for (int i=0; i<nread; i++)
{
printf("%04x\n", *p);
p++;
}
fclose(fp);
In addition, in C, you can access array elements either by subscription or by pointers arithmetic, the two are the same effect:
char arr[8];
arr[3] is same as *(arr + 3);
&arr[3] is same as arr + 3;
To read the big file by chunks:
fseek(fp, 0, SEEK_SET);
char buf[4096];
int nread;
int i;
while (1) {
nread = fread(buf, 1, 4096, fp);
for (i=0; i<nread; i++)
{
printf("%02x\n", buf[i]);
}
if (nread < 4096)
break;
}
fclose(fp);
I need to build a program that reads each record, and according to that record information would update some other records on the same file. For that, I was thinking in this approach:
int main(int argc, char *argv[]) {
FILE *my_file;
int files_read;
struct my_struct an_struct;
my_file = fopen("myfile.dat", "rb");
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
while (files_read == 1) {
do_update();
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("main->files_read: %d \n", files_read); //This prints one
}
fclose(archivo_paises);
return 0;
}
In the main function I'm reading the contents of the file, and every time I call read I get one as a response until I reach the end of the file. The problem is in the do_update function:
void do_update() {
FILE *my_file;
int files_read;
struct my_struct an_struct;
struct my_struct another_struct;
my_files = fopen("myfile.dat", "wb+"); //Using rb+ solves it
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
//This printed zero!. Prints one using rb+
while (files_read == 1) { //This never gets executed. Unless you use rb+
if(something){
fwrite(&another_struct, sizeof(struct my_struct), 1, my_file);
// Using rb+, this returns zero and didn't update
}
files_read = fread(&an_struct, sizeof(struct my_struct), 1, my_file);
printf("do_update->files_read: %d \n", files_read);
}
fclose(my_file);
}
What's happening is that the files_read variable gets the value of zero after the read call, so the logic to update the file is never executed.
Why is read returning zero when opening a file for wb+?
Update:
Using rb+ as file mode on do_update() works, but now the call to fwrite() always returns zero, and it didn't update the file. Is is related to the mode?
fwrite is moving the position in the file to the end of the file. The fread then has nothing to read.
Use fgetpos to save the file position before the fwrite, and fsetpos to set the position back after the fwrite.
The meaning of the flag "w+" (from http://www.cplusplus.com/reference/cstdio/fopen/):
write/update: Create an empty file and open it for update (both for input and output). If a file with the same name already exists its contents are discarded and the file is treated as a new empty file.
When you open a file with "w+", you will need to write to it first before you can read from it.
Update
Example program to demonstrate use of "rb+".
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void createFile(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* out = fopen(filename, "wb");
if ( out == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
data = rand()/10000;
fwrite(&data, sizeof(data), 1, out);
}
fclose(out);
}
void displayFileContents(char const* filename, int num)
{
int i = 0;
int data = 0;
FILE* in = fopen(filename, "rb");
if ( in == NULL )
{
return;
}
for (i = 0; i < num; ++i )
{
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
}
fclose(in);
}
void testReadAndWrite(char const* filename, int num)
{
int i = 0;
int data = 0;
long int pos = 0;
FILE* in = fopen(filename, "rb+");
if ( in == NULL )
{
return;
}
for ( i = 0; i < num; ++i )
{
pos = ftell(in);
fread(&data, sizeof(data), 1, in);
printf("%d\n", data);
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Write at the previus position.
data = rand();
printf("%d\n", data);
if ( fwrite(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to write using fwrite.\n");
}
// Rewind to previos position.
fseek(in, pos, SEEK_SET);
// Read from the previus position.
if ( fread(&data, sizeof(data), 1, in) != 1 )
{
printf("Unable to read using fread.\n");
}
printf("%d\n\n", data);
}
fclose(in);
}
int main()
{
char const* filename = "test.txt";
int num = 10;
// See the random number generator.
srand(time(NULL));
// Create a file with some random data.
createFile(filename, num);
// Display the contents of the file.
displayFileContents(filename, num);
printf("\n");
// Test read and write using a single FILE*
testReadAndWrite(filename, num);
}
Sample output:
51830
169074
141071
61921
145333
101195
139074
9535
164668
49552
51830
1030292590
1030292590
169074
1003635396
1003635396
141071
1060541073
1060541073
61921
474399692
474399692
145333
1467401071
1467401071
101195
830521014
830521014
139074
1186142943
1186142943
9535
1759682963
1759682963
164668
848798825
848798825
49552
60932215
60932215