Что мне делать, если сбой fclose?

#c #file #io

#c #файл #io

Вопрос:

 #include <stdio.h>

int main(void) {
    FILE *fp = fopen("hello.txt", "r");
    
    if (fp == NULL) {
        fputs("hello.txt failed to openn", stderr);
        return 0;
    }
    
    /* do some stuff with the file */
    
    if (fclose(fp) == EOF) {
        /* what should I do? we can't just leave a file open */
    }
    
    return 0;
}
  

fclose может произойти сбой, но если не удается закрыть файл, что мне делать? Мы не можем просто оставить файл открытым. Будем ли мы продолжать закрывать файл, пока он не завершится сбоем? Что бы вы, ребята, сделали?

Комментарии:

1. Если файл был открыт для чтения, никаких действий по исправлению ситуации предпринимать не стоит. Обратите внимание, что любой открытый файл будет закрыт системой при выходе из программы.

2. Если вы находитесь в размещенной среде, не напрягайтесь. Ваша программа не несет ответственности за устранение всех проблем в системе, в которой она работает. Вы можете напечатать описательную ошибку в stderr, а затем завершить процесс с кодом, сигнализирующим об ошибке.

3. Используйте fflush() для точек, где вам нужно выполнить запись в файл.

4. По крайней мере, в Linux на странице руководства для базового close(2) вызова указано не повторять попытку после ошибки, fwiw.

5. И что более важно, похоже, что стандарт гласит, что использование указателя ФАЙЛА для чего-либо после fclose() , независимо от того, возвращает он ошибку или нет, не определено.

Ответ №1:

Любое использование FILE указателя после его вызова fclose() (независимо от fclose() того, указывает ли он на ошибку или нет) является неопределенным поведением *.

Итак, лучшее, что вы можете сделать, это зарегистрировать ошибку и продолжить работу вашей программы. В зависимости от того, что он делает, также возможен выход со статусом ошибки.


* В разделе 7.21.3 проекта C11 говорится:

Значение указателя на файловый объект не определено после закрытия связанного файла

И в документации POSIX говорится:

После вызова fclose() любое использование stream приводит к неопределенному поведению.

Ответ №2:

Ошибка при включении fclose не означает, что система отказалась закрыть файл. Это редко должно происходить с файлами, открытыми для чтения, и тогда это может быть только следствием аппаратного сбоя или серьезной ошибки в файловой системе или ядре, а не с вещами, с которыми должна иметь дело обычная программа: просто зарегистрируйте или сообщите об ошибке, если можете. И в любом случае, после вызова fclose дескриптора больше никогда не следует использовать, независимо от того, произошла ошибка или нет.

Но когда файлы были открыты для записи и используется буферизация, fclose может возникнуть ошибка, если не удалось завершить последние операции записи, которые все еще находятся в очереди. Здесь причиной может быть ошибка превышения квоты, переполнение файловой системы или любая другая ошибка, о которой может сообщить fwrite . Таким образом, в этом случае ошибка on fclose может быть обработана так же, как вы обработали ошибки в предыдущем fwrite . Ни больше, ни меньше, за исключением того, что вы больше не можете использовать дескриптор файла.

Ответ №3:

Описание fclose в стандарте гласит:

  1. Успешный вызов fclose функции приводит к сбросу потока, на который указывает stream , и закрытию связанного файла. Любые неписаные буферизованные данные для потока доставляются в среду хоста для записи в файл; любые непрочитанные буферизованные данные отбрасываются. Независимо от того, выполняется ли вызов успешно или нет, поток отсоединяется от файла, и любой буфер, установленный функцией setbuf or setvbuf , отсоединяется от потока (и освобождается, если он был выделен автоматически).

Таким образом, если fclose сбой, то не совсем гарантировано, что дескриптор файла был переработан или файл был закрыт должным образом, но FILE на который указывает by stream , больше нельзя использовать, потому что файл был отделен от него, а буферы освобождены.

Обратите внимание, что это fclose может привести к сбою, например, если некоторые данные хранились в буферах, а на диске не хватает места. Если вы заботитесь о корректной записи данных, используйте fflush для очистки данных и обработки ошибок, например, попросите пользователя освободить больше места на диске или что-то подобное; в отличие от этого fclose , вы всегда можете повторить попытку fflush позже.