linux – fread. Not understandable error while reading. The stream is created but no reading occurs

Question:

A question for experts C. There is the following code:

  FILE *in_out = NULL;
  FILE *out = NULL;
  axis_t tmp_buf_now;  //struct
  memset(&tmp_buf_now, 0, sizeof(axis_t));
  const char *now = "now_data";  //file 1
  const char *previous = "previous_data";  //file 2

  in_out = fopen(now, "rb+");  //open binary file. Read and write mode
  if (!in_out) {
    if (errno == ENOENT) {  //No such file or directory
      in_out = fopen(now, "wb+");  //Create new file. Read and write mode
      if (!in_out) {
        perror("open");
        exit(EXIT_FAILURE);
      }
    }
  }

  if (!fread(&tmp_buf_now, sizeof(axis_t), 1, in_out)) { //exception - error2
    int en = errno;
    printf("errno %i\n", en);
    if (en != EAGAIN) {
      perror("fread");
      exit(EXIT_FAILURE);
    }
  }
  printf("old data\n x:%f, y:%f, z:%f\n", tmp_buf_now.x, tmp_buf_now.y,
         tmp_buf_now.z);

errno 2
fread: No such file or directory

What's wrong with the code?
PS: I am writing binary data. OS – linux. gcc -std = c99.

Answer:

Obviously, the question is considering the case when the file does not yet exist and the first call in_out = fopen(now, "rb+"); returns NULL . In this case, the variable errno , of course, takes on the value ENOENT .

The second call to fopen() successfully creates a file (empty).

Since successful calls do not change the value of errno , it remains the same after the call to fread() , which returns 0 (the file is empty), which in this case corresponds to EOF .

That. you are simply misinterpreting the situation and displaying a non-existent error message.

Note that man 3 fread says:

fread () does not distinguish between end-of-file and error, and callers must use feof (3) and ferror (3) to determine which occurred.


Perhaps the following modification of the code will clarify the situation.

...
  int old = 1;
  in_out = fopen(now, "rb+");  //open binary file. Read and write mode
  if (!in_out) {
    if (errno == ENOENT) {  //No such file or directory
      in_out = fopen(now, "wb+");  //Create new file. Read and write mode
      if (!in_out) {
        perror("open");
        exit(EXIT_FAILURE);
      } else { 
        tmp_buf_now = (axis_t){1, 2, 3};
        fwrite(&tmp_buf_now, sizeof(axis_t), 1, in_out);
        old = 0; // write initial data to file
      }
    }
  }

  rewind(in_out); 
  errno = 0;
  if (!fread(&tmp_buf_now, sizeof(axis_t), 1, in_out)) { 
    int en = errno;
    printf("errno %i\n", en);
    if (feof(in_out))
      exit((puts("fread -- empty file"), EXIT_SUCCESS));
    else if (ferror(in_out))
      exit((perror("fread"), EXIT_FAILURE));
    else
      exit((perror("fread ???"), EXIT_FAILURE));
  }

  printf("%s data\n x:%f, y:%f, z:%f\n",
     old ? "old" : "new", tmp_buf_now.x, tmp_buf_now.y, tmp_buf_now.z);

Note the call to rewind() before fread() .

In this situation, when we create a file ourselves and write data to it, the read-write position after fwrite() will be at the end of the file and our fread() will return 0 in the same way as in the case of an empty file. Therefore, we call rewind() to position to the beginning of the file (it is clear that if an existing file is rewind() this rewind() does not affect anything) before reading.

Experiment with launching in cases with both an empty file and no file.

Scroll to Top