Подтвердить что ты не робот

Проверка возвращаемого значения fclose

Требуется ли проверить возвращаемое значение fclose? Если мы успешно открыли файл, каковы шансы его закрытия?

Спасибо!

С уважением, Джей

4b9b3361

Ответ 1

Когда вы fwrite в файл, он может ничего не писать, он может оставаться в буфере (внутри объекта FILE). Вызов fflush будет фактически записывать его на диск. Эта операция может выйти из строя, например, если вы просто закончили дисковое пространство или возникла некоторая другая ошибка ввода-вывода.

fclose также неявно стирает буферы, поэтому он может выйти из строя по тем же причинам.

Ответ 2

От comp.lang.c:

Вызов fclose() может завершиться неудачно и должен проверяться с ошибкой так же усердно как и все другие операции с файлами. Звучит педантично, верно? Неправильно. В бывшая жизнь, мой продукт компании удалось уничтожить данные клиента пропуская проверку на отказ, если закрытие файла. Последовательность что-то вроде (перефразировано):

stream = fopen(tempfile, "w"); 
if (stream == NULL) ... 
    while (more_to_write) 
        if (fwrite(buffer, 1, buflen, stream) != buflen) ... 
fclose (stream); 

/* The new version has been written successfully.  Delete 
 * the old one and rename. 
 */ 
remove (realfile); 
rename (tempfile, realfile); 

Конечно, случилось так, что fclose() закончилось использование дискового пространства написать последние пару блоков данных, поэтому "tempfile" был усечен и непригодным для использования. А так как fclose() отказ не был обнаружен, программа пошел прямо вперед и уничтожил наилучшая версия данных в благосклонность поврежденной версии. И в качестве У Мерфи было бы это, жертва в этот конкретный инцидент был лицо, отвечающее за отдел, лицо с полномочиями купить больше нашего продукта или заменить это с конкурирующим продуктом - и, natch, человек, который уже недовольны нами по другим причинам.

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

ПРОВЕРЬТЕ КОДЫ НЕИСПРАВНОСТИ!

Ответ 3

Вы могли (и должны) сообщить об ошибке, но в некотором смысле поток все еще закрыт:

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

Ответ 4

  • fclose() перед тем, как вернуться, выровнят любой неписанный вывод (через fflush()), поэтому ошибка, полученная из базового write(), не будет отображаться в fwrite() или fprintf(), но когда вы делаете fclose(). В результате любая ошибка, которую может генерировать write() или fflush(), может быть сгенерирована с помощью fclose().

  • fclose() также вызовет close(), который может генерировать ошибки для клиентов NFS, где измененный файл фактически не загружается на удаленный сервер до close() времени. Если NFS-сервер потерпел крах, то close() завершится с ошибкой, и, таким образом, fclose() также завершится с ошибкой. Это может быть справедливо для других сетевых файловых систем.

Ответ 5

Вы должны ВСЕГДА проверить результат fclose()

Ответ 6

Предположим, вы генерируете данные. У вас есть старые данные, которые вы fread() из файла, а затем выполняете некоторую обработку данных, генерируете больше данных и затем записываете их в новый файл. Вы стараетесь не перезаписывать старый файл, потому что знаете, что попытка создать новый файл может завершиться неудачей, и вы хотели бы сохранить свои старые данные в этом случае (некоторые данные лучше, чем никакие данные). По завершении всех fwrite() s, которые все успешны (потому что вы тщательно проверили возвращаемое значение из fwrite()), вы fclose() файл. Затем вы rename() ваш только что записанный файл и перезапишите старый файл.

Если fclose() не удалось из-за ошибки записи (полный диск?), вы просто перезаписали свой последний хороший файл с чем-то, что может быть нежелательным. К сожалению.

Итак, если это важно, вы должны проверить возвращаемое значение fclose().

В терминах кода:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *ifp = fopen("in.dat", "rb");
    FILE *ofp = fopen("out.dat", "wb");
    char buf[BUFSIZ];
    size_t n;
    int success = 1;

    if (ifp == NULL) {
        fprintf(stderr, "error opening in.dat\n");
        perror("in.dat");
        return EXIT_FAILURE;
    }

    if (ofp == NULL) {
        fclose(ifp);
        fprintf(stderr, "error opening out.dat\n");
        perror("out.dat");
        return EXIT_FAILURE;
    }

    while ((n = fread(buf, 1, sizeof buf, ifp)) > 0) {
        size_t nw;
        if ((nw = fwrite(buf, 1, n, ofp)) != n) {
            fprintf(stderr, "error writing, wrote %lu bytes instead of %lu\n",
                            (unsigned long)n,
                            (unsigned long)nw);
            fclose(ifp);
            fclose(ofp);
            return EXIT_FAILURE;
        }
    }
    if (ferror(ifp)) {
        fprintf(stderr, "ferror on ifp\n");
        fclose(ofp);
        fclose(ifp);
        return EXIT_FAILURE;
    }

#ifdef MAYLOSE_DATA
    fclose(ofp);
    fclose(ifp);
    rename("out.dat", "in.dat"); /* Oops, may lose data */
#else
    if (fclose(ofp) == EOF) {
        perror("out.dat");
        success = 0;
    }
    if (fclose(ifp) == EOF) {
        perror("in.dat");
        success = 0;
    }
    if (success) {
        rename("out.dat", "in.dat"); /* Good */
    }
#endif
    return EXIT_SUCCESS;
}

В приведенном выше коде мы были осторожны в отношении fopen(), fwrite() и fread(), но даже тогда не проверка fclose() может привести к потере данных (при компиляции с MAYLOSE_DATA).

Ответ 7

В справочной странице fclose указано, что она может завершиться неудачно по любой причине, которая может завершиться с закрытием или fflush.

Цитирование:

Системный вызов close() не будет выполнен, если:

 [EBADF]            fildes is not a valid, active file descriptor.

 [EINTR]            Its execution was interrupted by a signal.

 [EIO]              A previously-uncommitted write(2) encountered an
                    input/output error.

fflush может завершиться ошибкой по причинам, из-за которых write() потерпит неудачу, в основном в том случае, если вы не можете писать в/сохраните файл.

Ответ 8

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

Ответ 9

Я видел много раз fclose(), возвращающих ненулевое значение.

И при тщательной проверке выяснилось, что фактическая проблема заключалась в записи, а не в fclose.

Поскольку записываемый материал буферизуется до того, как произойдет фактическая запись, и когда вызывается fclose(), весь буфер очищается. Таким образом, любая проблема в написании буферизованного суффикса, например, как полный диск, появляется во время fclose(). Как говорит Дэвид Йелл, для написания пуленепробиваемого приложения вам нужно рассмотреть возвращаемое значение fclose().

Ответ 10

Если в контексте вашего приложения вы можете придумать что-нибудь полезное, если fclose() терпит неудачу, а затем проверьте возвращаемое значение. Если вы не можете, не делайте этого.

Ответ 11

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

Чтобы избежать проблем и обеспечить (насколько это возможно из программы C), я предлагаю вам:

  • Правильно обрабатывать ошибки, возвращаемые fwrite().
  • Вызов fflush() перед закрытием потока. Не забывайте проверять ошибки, возвращаемые fflush().