Второй аргумент fopen - PullRequest
       7

Второй аргумент fopen

0 голосов
/ 24 января 2011

ОК, я пишу игру, и в этой игре есть интерактивное меню настроек.Что я хочу сделать, это записать в файл, если он не существует, прочитать из файла, если он существует, применить настройки, указанные в файле, и перезаписать его новыми настройками от пользователя, если пользователь решит изменить настройки,Так что это будет выглядеть примерно так (псевдо-код):

if (file does not exist)
    write_defaults
open settings
read from file
apply settings specified in file
while (user is changing settings)
    if (user is done) break
write new settings to file
apply new settings

Теперь, что бы я использовал для второго аргумента fopen?Я пробовал оба "r +" и "w +", но у меня были проблемы с обоими.

Ответы [ 3 ]

2 голосов
/ 24 января 2011

Я бы открыл как "w" для операций записи и заново открыл бы как "r" для операций чтения, если только вы не выполняете какое-то одновременное чтение / запись с произвольным доступом.

Как @Стефан упомянул в комментарии ниже, вы бы хотели "rb" или "wb", если вы манипулируете необработанными двоичными данными, а не текстом.

0 голосов
/ 24 января 2011

Просто откройте файл с помощью «r +».Проверьте возвращенный указатель, если указатель не NULL, считайте настройки из файла.Затем запишите в файл.

0 голосов
/ 24 января 2011

Использование "r+" правильно для первой попытки; Если это не удается из-за того, что файл не существует, попробуйте еще раз с "w+". Это дает вам файл, открытый для обновления, но не блокирует файл, если он уже существует.

Однако это неоптимально в том смысле, что существует уязвимость TOCTOU (время проверки, время использования) - если файл создается между неудачным открытием с помощью "r+" и успешным открытием с помощью "w+", информация в файле будет потеряна.

Если у вас есть доступ к функциям POSIX, вы можете использовать open() вместо fopen() для правильного выполнения работы за одну атомарную попытку, а затем fdopen() для преобразования дескриптора файла в поток файлов.

FILE *carefully_open(const char *file)
{
    int fd = open(file, O_RDWR | O_CREAT, 0644);
    FILE *fp = 0;

    if (fd >= 0)
        fp = fdopen(fd, "r+");
    if (fd >= 0 && fp == 0)
        close(fd);
    return fp;
}

Единственным недостатком этого является то, что он создаст файл через неработающую символическую ссылку. Вы можете избежать этого с помощью флага O_EXCL, но тогда открытие не удастся, если файл существует. В конце концов вы в конце концов сделаете два звонка на open(), один с просто O_RDRW, а второй с O_RDRW | O_CREAT | O_EXCL, чтобы обезопасить себя от следования прерванных сообщений.

(Что такое неработающая символическая ссылка? Если в текущем каталоге нет файла pqr, ln -s ./pqr xyz означает, что xyz - это поврежденная символическая ссылка, которая будет 'исправлена' путем создания файла 'pqr' с open() вызов показан.)

Какие у вас были проблемы?

...