nahumd
asked on
How to write to a file, rewind, write again
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.
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.
>>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 );
}
}
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 );
}
}
ASKER
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.
I need to change an existing file, and open the file with "a+" access mode, and then the fseek command doesn't work well.
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
"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
ASKER
Thanks garethwebbley, this looks good.
I will close the question after I test it, to see if it doesn't open any problems.
Thanks !
I will close the question after I test it, to see if it doesn't open any problems.
Thanks !
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.
Thank you garethwebbley, too, for your working solution, but ewest's solution is simpler, and thus better.
ASKER
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.