Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как выбрать открытый режим с помощью fopen()?

Автор вопроса: Summer_More_More_TeaОтветов: 3

У меня проблема с режимом открытия файла с 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 */
}
  • Можете ли вы опубликовать соответствующий код здесь? P.P 13.05.2012
  • Мне любопытно .. почему вы ищете / пишете за пределами EOF? OrionRogue 13.05.2012
  • @OrionRogue Я использую файл для эмуляции жесткого диска. Данные считываются и записываются порциями. Значит изначально файл пустой, данные могут отставать EOF Summer_More_More_Tea 13.05.2012

cfile-iolinuxfopen

Ответы

Ответ 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() с помощью флагов.

Ответ 2 · рейтинг 2 · geekosaur

Файловые режимы четко задокументированы для fopen (попробуйте man 3 fopen в Unix/Linux/OS X).

r+ Открыт для чтения и записи. Поток располагается в начале файла.

Ответ 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

=============================

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы