3
votes

What is the difference between fread and fgets when reading in from a file? I use the same fwrite statement, however when I use fgets to read in a .txt file it works as intended, but when I use fread() it does not.

I've switched from fgets/fputs to fread/fwrite when reading from and to a file. I've used fopen(rb/wb) to read in binary rather than standard characters. I understand that fread will get /0 Null bytes as well rather than just single lines.

  //while (fgets(buff,1023,fpinput) != NULL) //read in from file
  while (fread(buff, 1, 1023, fpinput) != 0) // read from file

I expect to read in from a file to a buffer, put the buffer in shared memory, and then have another process read from shared memory and write to a new file.

When I use fgets() it works as intended with .txt files, but when using fread it adds a single line from 300~ characters into the buffer with a new line. Can't for the life of me figure out why.

1
fgets stops reading when it encounted a line feed. fread doesn't check for those.ikegami
fgets adds a NUL. fread doesn't.ikegami
Did you treat the buf as a NUL-terminated string when it wasn't?ikegami
Really?? fread reads a specified number of (raw binary) bytes, while fgets reads a text line up to end-of-line char. And appends null. You can use fread on text files, but fgets on binary usually isn't a good idea. Don't skip your C lectures ;)ddbug
I'm trying to convert it all to only using fread()/fwrite(). But when I use fgets it results in : prnt.sc/neq45x But when I use fread() it results in: prnt.sc/neq4bzRemilia Scarlet

1 Answers

2
votes

fgets will stop when encountering a newline. fread does not. So fgets is typically only useful for text files, while fread can be used for both text and binary files.

From the C11 standard:

7.21.7.2 The fgets function

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.

7.21.8.1 The fread function

The fread function reads, into the array pointed to by ptr, up to nmemb elements whose size is specified by size, from the stream pointed to by stream. For each object, size calls are made to the fgetc function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object. The file position indicator for the stream (if defined) is advanced by the number of characters successfully read. If an error occurs, the resulting value of the file position indicator for the stream is indeterminate. If a partial element is read, its value is indeterminate.

This snippet maybe will make things clearer for you. It just copies a file in chunks.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv)
{
    if(argc != 3) {
        printf("Usage: ./a.out src dst\n");
        printf("Copies file src to dst\n");
        exit(EXIT_SUCCESS);
    }

    const size_t chunk_size = 1024;

    FILE *in, *out;
    if(! (in = fopen(argv[1], "rb"))) exit(EXIT_FAILURE);
    if(! (out = fopen(argv[2], "wb"))) exit(EXIT_FAILURE);

    char * buffer;
    if(! (buffer = malloc(chunk_size))) exit(EXIT_FAILURE);

    size_t bytes_read;

    do {
        // fread returns the number of successfully read elements
        bytes_read = fread(buffer, 1, chunk_size, in);

        /* Insert any modifications you may */
        /* want to do here                  */

        // write bytes_read bytes from buffer to output file
        if(fwrite(buffer, 1, bytes_read, out) != bytes_read) exit(EXIT_FAILURE);
   // When we read less than chunk_size we are either done or an error has 
   // occured. This error is not handled in this program. 
    } while(bytes_read == chunk_size); 


    free(buffer);
    fclose(out);
    fclose(in);
}

You mentioned in a comment below that you wanted to use this for byteswapping. Well, you can just use the following snippet. Just insert it where indicated in code above.

for(int i=0; i < bytes_read - bytes_read%2; i+=2) {
    char tmp = buffer[i];
    buffer[i] = buffer[i+1];
    buffer[i+1] = tmp;
}