У меня проблема с режимом открытия файла с fopen().
В моем случае я хочу свободно искать курсор, иногда даже за пределами EOF. Более того, я также хочу добавить к нему вместо усечения существующего файла. Я попытался открыть файл в режиме a+; однако я не могу свободно искать файловый курсор. Каждый раз, когда я ищу курсор за пределами EOF, новые данные о поступлении будут добавляться в конец файла, а не в указанную мной позицию. В то время как, если открыть в режиме w+, существующий файл будет обрезан. Есть ли идеальное решение этой проблемы?
ОБНОВИТЬ:
Один неясный момент заключается в том, что файл не всегда может существовать; В этом случае мне нужно создать новый файл.
На самом деле я хочу обработать файл конфигурации. Я не знаю, является ли это хорошей практикой для такой реализации. Или я должен сначала разместить пустой файл конфигурации. Таким образом, нет необходимости заботиться о том, что материалы дела не существуют?
Ниже приведен фрагмент кода:
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 */
}
Ответ 1 · рейтинг 6 · Jonathan Leffler
Вам придется иметь дело с возможно несуществующим файлом в два этапа, сначала предполагая, что он есть, а затем разбираясь с его отсутствием:
if ((f = fopen(filename, "rb+") == 0)
f = fopen(filename, "wb+");
if (f == 0)
...report error...
Режим "rb+" не сможет открыть несуществующий файл (но в остальном ведет себя так, как вы хотите). Если файл не существует, то вместо этого "wb+" сделает то, что вы хотите (хотя это все равно может привести к сбою, например, если файл существует, но у вас нет разрешения на запись в него). Вы должны надеяться, что вы не подверглись атаке TOCTOU (Time of Check, Time of Use) с двойной попыткой.
Альтернативный подход использует 3-аргументную версию системного вызова open() с соответствующими флагами для открытия файлового дескриптора, а затем использует fdopen() для создания файлового потока из файлового дескриптора:
#include <fcntl.h>
int fd;
if ((fd = open(filename, O_RDRW | O_CREAT, 0644)) >= 0)
f = fdopen(fd, "rb+");
Вы получаете довольно точный контроль над open() с помощью флагов.
Ответ 3 · рейтинг -1 · vincent
Привет, вы можете использовать "w +" для чтения и записи с помощью fseek, я написал небольшую демонстрационную программу, сначала записывайте данные в файл и используйте fseek, чтобы сделать каждые данные интервалами некоторого байта, а затем прочитать его:
#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;
}
=============================== результат следующим образом:
Текущий шаг: 0, значение = 0
Шаг шага: 64, значение = 1
Шаг шага: 128, значение = 2
Шаг шага: 192, значение = 3
Шаг шага: 256, значение = 4
Шаг шага: 320, значение = 5
Шаг шага: 384, значение = 6
Шаг шага: 448, значение = 7
Шаг шага: 512, значение = 8
Шаг шага: 576, значение = 9
Cur Step: 640, значение = 10
Шаг шага: 704, значение = 11
Cur Step: 768, значение = 12
Шаг шага: 832, значение = 13
Шаг шага: 896, значение = 14
Шаг Cur: 960, значение = 15
Шаг шага: 1024, значение = 16
Шаг шага: 1088, значение = 17
Шаг шага: 1152, значение = 18
Шаг шага: 1216, значение = 19
=============================