File I/O functions in C

Differences between fread and fgets

During my office hour, several students asked me, since both fread() and fgets() can be used to read files, what is the difference between them?

My short answer is that the intent is different, what type of data do you expect to read in? For regular text, use fgets(); for binary or unspecified, use fread().1

However, what exactly is the difference between them? Let’s dive into it together.

Different call parameters

char *fgets(char *s, int size, FILE *stream);

The way to use fgets() is really simple, just tell it where I want the characters to be stored (s), the length I want them to be read (size)2, and where I want them to be retrieved from (stream).

size_t fread(const void *ptr, size_t size, size_t n, FILE *stream);

For fread(), in addition to ptr and stream, which correspond to the s and stream in fgets() respectively, we need to provide two more parameters: the length of each element, size, and the total number of elements we want to read, n.3

Different return types

fgets() will simply return s on success, and NULL on error or unexpected situations.

However, fread() return the number of items read. It is always smaller or equal to the third parameter n and equals the number of bytes being read only when the second parameter size is 1.

Here is an example:

char buf[8];
int r1 = fread(buf, sizeof(char), 8, fp);
int r2 = fread(buf, sizeof(int), 2, fp);

In case of success, those two lines will both read in 8 bytes (1 * 8 = 4 * 2 = 8) from the file fp and filled up the whole buffer. However, return value for the first line r1 will be 8, since 8 1-byte elements have been transferred; while return value for the second line r2 will be 2, since only 2 4-byte elements have been transferred in this case.

Different reading lengths

Since fgets() is looking for regular text and guarantees to null-terminate the target buffer, but fread() only responsible for reading in arbitrary data, there is a 1-byte different for there reading length.

Take the following as an example:

char buf[8];
fgets(buf, sizeof(buf), fp);
fread(buf, 1, sizeof(buf), fp);

Although it is undoubtedly true that buf has a length of 8 bytes. But when we use fgets(), it reads at most 7 bytes from file fp and writes those 7 bytes to buf along with '\0'. Whereas fread() will literally read 8 bytes from the fp file.

Different unblock conditions

We all know that asking the system to read something may block the program until some trigger conditions are met. The unblock scenario for these two functions is as follows.

For fgets():

  • Encounter '\n'
  • Fill up buffer for length (n - 1)
  • Error
  • End of file (EOF)

For fread():

  • Fill up buffer for length (n)
  • Error
  • End of file (EOF)

Use Case Demonstration

We can write some simple programs to compare these two functions.

For fgets() we have the following C program:

char *buf = malloc(maxlen);
FILE *fp = fopen(filename, "rb");
while (fgets(buf, maxlen, fp) != NULL) {
    display_for_one_round(buf, strlen(buf) + 1);
}

For fread() we have:

int length;
char *buf = malloc(maxlen);
FILE *fp = fopen(filename, "rb");
while (length = fread(buf, 1, maxlen, fp)) {
    display_for_one_round(buf, length);
}

And we also have two files, in test1.txt we have regular characters (contains \n) inside, while in test2.bin we have some characters (contains \n) and other random characters/symbols there.

The testing results are as follows:

fread_vs_fgets-regular

And

fread_vs_fgets-binary

The io_explore executable and two testing files are located at ~ax2155/public/io_explore/ directory on the server, you are free to check it out and try by yourself.4


  1. In case of any inconsistency, please refer to the professor’s lecture notes. ↩︎

  2. See following Part-3 for the details of this length. ↩︎

  3. See Part-2 for details between these two. ↩︎

  4. This is a program written by myself. If you found any issues, please feel free to come to my OH or e-mail me. ↩︎

Alex Jiakai XU
Alex Jiakai XU
Computer Science Student

My research interests include computer systems, programming languages, software designing, and cyberspace security.