Guillermo Guardastagno
Guillermo Guardastagno

Reputation: 547

C: One pointer for reading and one pointer for updating the same file

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?

Upvotes: 3

Views: 977

Answers (2)

R Sahu
R Sahu

Reputation: 206567

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

Upvotes: 4

Doug Currie
Doug Currie

Reputation: 41170

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.

Upvotes: 4

Related Questions