Reputation: 13446
I have a problem about file open mode with fopen()
.
In my case, I want to seek the cursor freely, may be even beyond EOF
sometimes. What's more, I also want to append to it instead of truncating the existing file. I tried to open the file in a+
mode; however, I cannot seek file cursor freely. Each time I seek the cursor beyond EOF
, new arrival data will be append to end of the file, not the position I specified. While, if open in w+
mode, the existing file will be truncated. Is there a perfect solution to this problem?
UPDATE:
One point not clearly specified is that the file may not always exist; I have to create a new file in that case.
In fact, I want to process a configuration file. I don't know whether it is good practice to implement like this. Or should I first place an empty configuration file. Thus there is no need to care about the case file does not exist?
Below is the code snippet:
FILE *f = fopen(FILE_PATH, "wb+");
struct record r;
if (f) {
if (fread((void *)&r, 1, sizeof(struct record), f) {
/* File exists, do the normal flow */
} else {
if (feof(f)) {
/* File is newly created, do some initialization */
}
}
} else {
/* issue a warning */
}
Upvotes: 3
Views: 17476
Reputation: 138
Hi, you can use "w+" to read and write by fseek, i wrote a little demo program, write data to file first and use fseek to make each data intervals some byte, and then read it:
#include <stdio.h>
#include <unistd.h>
#define FILE_PATH "seek_test.txt"
#define STEP_SIZE 64
void set_data(FILE* fp)
{
int i = 0;
fseek(fp, 0, SEEK_SET);
for ( ; i < 20; ++i)
{
fprintf(fp, "%d", i);
fseek(fp, STEP_SIZE, SEEK_CUR);
}
}
void get_data(FILE* fp)
{
int i = 0;
fseek(fp, 0, SEEK_SET);
for ( ; i < 20; ++i)
{
fscanf(fp, "%d", &i);
fprintf(stderr, "Cur Step: %5ld, value = %4d\n", i * STEP_SIZE, i);
fseek(fp, STEP_SIZE, SEEK_CUR);
}
}
int main(int argc, char* argv[])
{
FILE* fp = fopen(FILE_PATH, "w+");
if (fp == NULL)
{
printf("fopen Error\n");
exit(0);
}
set_data(fp);
get_data(fp);
return 0;
}
=============================== result as follows:
Cur Step: 0, value = 0
Cur Step: 64, value = 1
Cur Step: 128, value = 2
Cur Step: 192, value = 3
Cur Step: 256, value = 4
Cur Step: 320, value = 5
Cur Step: 384, value = 6
Cur Step: 448, value = 7
Cur Step: 512, value = 8
Cur Step: 576, value = 9
Cur Step: 640, value = 10
Cur Step: 704, value = 11
Cur Step: 768, value = 12
Cur Step: 832, value = 13
Cur Step: 896, value = 14
Cur Step: 960, value = 15
Cur Step: 1024, value = 16
Cur Step: 1088, value = 17
Cur Step: 1152, value = 18
Cur Step: 1216, value = 19
=============================
Upvotes: -1
Reputation: 754900
You will have to deal with the possibly non-existent file in two stages, first assuming that it is there and then dealing with its absence:
if ((f = fopen(filename, "rb+") == 0)
f = fopen(filename, "wb+");
if (f == 0)
...report error...
The "rb+"
mode will fail to open a non-existent file (but otherwise behaves as you want). If the file doesn't exist, then "wb+"
will do what you want instead (though it could still fail, for example if the file exists but you don't have permission to write to it). You have to hope that you've not been subjected to a TOCTOU (Time of Check, Time of Use) attack with the double attempt.
An alternative approach uses the 3-argument version of the open()
system call with appropriate flags to open a file descriptor, and then uses fdopen()
to create a file stream from the file descriptor:
#include <fcntl.h>
int fd;
if ((fd = open(filename, O_RDRW | O_CREAT, 0644)) >= 0)
f = fdopen(fd, "rb+");
You get rather precise control over open()
with the flags.
Upvotes: 6
Reputation: 61459
The file modes are clearly documented for fopen
(try man 3 fopen
on Unix/Linux/OS X).
r+
Open for reading and writing. The stream is positioned at the beginning of the file.
Upvotes: 2