How to write to a file, rewind, write again

nahumd
nahumd used Ask the Experts™
on
Hi,
I need a way to open an existing file, adding some text in the end, rewind the file to where I opened it, and replace the text with another one.

For example:
if the text file looks like:

aa
bb

I want to open it, and add:
aa
bb
cc

and then (in the same iteration), rewind the file and replace the "cc" with "dd" :
aa
bb
dd

I've tried to use fseek, but it doesn't seems to work with fopen (....,"a+") function. I've also tried to print backspace, but that didn't work either.
Any help would be appreciated.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
P.S.
The platform is windows 2000/Visual C++ 6.
If there is a way to do it with a file handle that returned by the fopen (...,"a+") command, it would be better.
If it can't be done, other ways would be fine too.
jkr
Top Expert 2012

Commented:
>>If there is a way to do it with a file handle that returned by the fopen (...,"a+") command

Yes. Use 'fseek()' to 'move' inside a file, e.g.

/* FSEEK.C: This program opens the file FSEEK.OUT and
 * moves the pointer to the file's beginning.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[81];
   int  result;

   stream = fopen( "fseek.out", "w+" );
   if( stream == NULL )
      printf( "The file fseek.out was not opened\n" );
   else
   {
      fprintf( stream, "The fseek begins here: "
                       "This is the file 'fseek.out'.\n" );
      result = fseek( stream, 23L, SEEK_SET);
      if( result )
         perror( "Fseek failed" );
      else
      {
         printf( "File pointer is set to middle of first line.\n" );
         fgets( line, 80, stream );
         printf( "%s", line );

      }
      fclose( stream );
   }
}

Author

Commented:
The problem is that you opened the file with "w+" access mode. In this mode the fseek command works well.
I need to change an existing file, and open the file with "a+" access mode, and then the fseek command doesn't work well.
Ensure you’re charging the right price for your IT

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Just found this on the man page for fopen

"Opening a file with append mode (a as the first character in the mode argument) causes all subsequent writes to the file to be forced to the then current end-of-file, regardless of intervening calls to fseek()."

One way I can think of to do this is to open a file descriptor using open (Note under windows the prototype for this is defined in io.h, on *nix it's defined in unistd.h). Once opened you can convert this to a stream using fdopen with a mode of "w+".  The difference with fdopen is that it will not truncate the file if opened with "w+".  To append to the file you can just use fseek to get to the end of the file and then write as necessary.  You can then use fseek to position the file pointer to the desired point in the file and overwrite what you've just written.

Here's some example code which achieves what you've set out in your example :-

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>

int main( int argc, char *argv[] )
{
     int      fd;
     FILE *stream;
     char line[81];
     int  result;
     struct stat file_stats;
     char filename[] = "fseek.out";
     long end_pos=0;

     if ( stat( filename, &file_stats ) != -1 )
          end_pos = file_stats.st_size;
     else
          return(EXIT_FAILURE);

     fd = open( filename, O_RDWR );
     if( fd == -1 || (stream = fdopen(fd, "w+")) == NULL)
          printf( "The file fseek.out was not opened\n" );
     else
     {
          fseek(stream, 0, SEEK_END);
          fprintf( stream, "cc\n" );
          result = fseek( stream, end_pos, SEEK_SET);
          if( result )
               perror( "fseek failed" );
          else
          {
               printf( "File pointer is set to the point at which we just written.\n" );
               fgets( line, sizeof(line), stream);
               printf( "%s", line );
          }
          result = fseek( stream, end_pos, SEEK_SET);
          if( result )
               perror( "Fseek failed" );
          else
               fprintf( stream, "dd\n" );
          result = fseek( stream, end_pos, SEEK_SET);
          if( result )
               perror( "Fseek failed" );
          else
          {
               printf( "File pointer is set to the point at which we just written.\n" );
               fgets(line, sizeof(line), stream);
               printf( "%s", line );
          }
          fclose( stream );
     }
     return(EXIT_SUCCESS);
}
 

You'll probably want to use ftell or fgetpos to get the position rather than using stat to find out the size of the file.

Hope this helps

Author

Commented:
Thanks garethwebbley, this looks good.
I will close the question after I test it, to see if it doesn't open any problems.

Thanks !
Commented:
Why use open and fdopen??? Keep it simple with

    fopen(filename, "r+")

The "r+" mode opens a file for reading and writing w/o truncation.

Author

Commented:
You're right, of course, ewest. This is the straight forward solution I was hoping to get.
Thank you garethwebbley, too, for your working solution, but ewest's solution is simpler, and thus better.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial