-1

I would like to read the data with fread from file. However, I encounter the problem of setting of NULL terminator.I think the the line (fileMem[fileSize] = 0;) should have been solved. However, I still get rubbish at the with I check the value of "fileMem". Would anyone help me to find the problem?

I followed other posts about setting the NULL terminator but just does not work

File *input = fopen(filePath, "r");
fseek(input, 0, SEEK_END);
auto fileSize = ftell(input);
fseek(input, 0, SEEK_SET);
char* fileMem = new char[fileSize+1];
fileMem[fileSize] = 0;// the NULL terminator problem should have been solved here
clearerr(input);
fread(fileMem, fileSize,1, input);

What is the problem with my code?

Carl
  • 65
  • 2
  • 12
  • 1
    I would try swapping the middle arguments. `fread(fileMem, 1, fileSize, input);`. – R Sahu Mar 24 '16 at 16:53
  • 2
    why are you using C file api in C++ program? – SergeyA Mar 24 '16 at 16:53
  • The second example in this answer shows how to read in a binary file at once in C++: http://stackoverflow.com/a/5420568/104774 – stefaanv Mar 24 '16 at 17:03
  • Another one (here for text file): http://stackoverflow.com/a/19922123/104774 – stefaanv Mar 24 '16 at 17:07
  • @SergeyA: Personally, I always prefer the C I/O library in C++. It's at least possible to write UTF-8 to a file in Windows that way without jumping through flaming hoops. And since most of the files I work with in C++ are binary formats anyway, I gain nothing from iostreams, so I prefer the simplicity of the C API. – Cameron Mar 24 '16 at 17:22
  • @Cameron, interestingly enough, it's always the opposite for me in terms of simplicty. I find streams much simpler! I am always confused about number of records vs record size in `fread()`. Also the fact that it returns the number of records read (but what if a record was read partially??) means it's a showstopper for me. I use either streams or POSIX `read()`, but never `fread()` – SergeyA Mar 24 '16 at 17:33

3 Answers3

1

fread is reading more bytes than fileSize, because you are specifying a record size of fileSize, and asking it to read only one text record. It then overwrites the 0 at the end with actual data, so you get garbage.

fread returns the number of bytes it actually read, so you can allocate a bigger buffer, then use the return value from fread to determine how much of it is valid (and to set a null-terminator).

Since it is updating your data in this way, I also suggest changing the file type to binary ("rb" rather than "r" in call to fopen).

The reason this is happening is because fread performs translation of text when in text mode ("r" rather than "rb"), such as carriage returns and line feeds.

Matt Jordan
  • 2,080
  • 7
  • 10
1

Assuming you are on Windows, I think the problem is that you are opening the file in text mode and using fread which is meant for binary mode. In text mode, what you read may not be exactly what is in the file. Windows text files have "\r\n" at the end of the file, but in text mode this two character combination is converted to a single character, "\n". So the fileSize you computed will be too large and so your null terminator will be in the wrong place.

To verify this, change your fread to be:

int nr = fread( fileMen, 1, fileSize, input);

Swapping the middle args, will have fread return the number of bytes read. If you look at the value of nr, it will be smaller than fileSize because of the line end translation.

This wouldn't be a problem on a *nix system since there is no translation there in text mode.

pcarter
  • 1,362
  • 14
  • 20
0

When you want to use fread to read the contents of a file, you must open the file in binary mode.

FILE *input = fopen(filePath, "rb");
                                ^^

Otherwise, the size of the file you get by using

fseek(input, 0, SEEK_END);
auto fileSize = ftell(input);

will be greater than the number of characters that what can be read by fread.

If you have a CR and a LF, they will count as two characters by the above method but fread will read only one character. Hence, fread will read less than fileSize characters. You can also change the fread line to:

// Swap the middle arguments.
// The first argument is supposed to be the size of each object.
// The second argument is supposed to be the number of objects to read.
auto n = fread(fileMem, 1, fileSize, input);
if ( n != fileSize )
{
   // Surprise
}
fileMem[n] = '\0';
R Sahu
  • 196,807
  • 13
  • 136
  • 247