ZetCode

C ferror 函数

最后修改日期:2025 年 4 月 6 日

为确保程序可靠性,错误处理在文件操作中至关重要。ferror 函数有助于检测文件 I/O 操作中的错误。本教程通过实际示例深入讲解 ferror。您将学会如何检查文件操作错误并妥善处理它们。掌握 ferror 能使 C 程序中的文件处理更加健壮。

什么是 ferror?

ferror 函数检查文件操作中是否发生错误。它以 FILE 指针作为唯一参数。如果检测到错误,该函数将返回非零值。与检查文件结束的 feof 不同,ferror 专门检测读/写错误。在使用文件流之前,务必使用 clearerr 清除错误。

ferror 的基本用法

此示例演示了使用 ferror 检查文件操作错误的最简单方法。

basic_ferror.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("nonexistent.txt", "r");
    
    if (fp == NULL) {
        perror("File opening failed");
        return 1;
    }

    // Attempt to read from file
    int ch = fgetc(fp);
    
    if (ferror(fp)) {
        perror("Error reading file");
        clearerr(fp);  // Clear the error flag
    }

    fclose(fp);
    return 0;
}

此代码尝试打开一个可能不存在的文件并从中读取。读取操作后,ferror 检查是否发生了错误。clearerr 函数会重置错误标志,以便后续操作。请注意,我们仍然单独检查 fopen,因为它直接设置 errno

写操作后检查 ferror

ferror 也可以检测写操作中的错误,如本示例所示。

write_error.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("/readonly/test.txt", "w");
    
    if (fp == NULL) {
        perror("File opening failed");
        return 1;
    }

    // Attempt to write to a potentially read-only location
    fprintf(fp, "Test data");
    
    if (ferror(fp)) {
        perror("Error writing to file");
        clearerr(fp);
    }

    fclose(fp);
    return 0;
}

在此,我们尝试将内容写入可能位于只读位置的文件。写操作尝试后,ferror 检查操作是否成功。错误消息有助于诊断权限问题。为进行全面的错误处理,请务必同时检查 fopenferror

ferror 在文件复制程序中的应用

此示例展示了 ferror 在实际文件复制应用程序中的用法。

file_copy.c
#include <stdio.h>

int main() {
    FILE *src = fopen("source.txt", "r");
    FILE *dest = fopen("destination.txt", "w");
    
    if (src == NULL || dest == NULL) {
        perror("File opening failed");
        return 1;
    }

    int ch;
    while ((ch = fgetc(src)) != EOF) {
        fputc(ch, dest);
        
        if (ferror(src) || ferror(dest)) {
            perror("File operation error");
            clearerr(src);
            clearerr(dest);
            break;
        }
    }

    fclose(src);
    fclose(dest);
    return 0;
}

该程序将内容从 source.txt 复制到 destination.txt。每次字符传输后,ferror 都会检查两个文件是否存在错误。如果发生错误,循环将立即中断。这确保我们能检测到复制过程中出现的磁盘已满等问题。

使用 ferror 处理二进制文件

二进制文件操作也可从 ferror 检查中受益,如本示例所示。

binary_error.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("data.bin", "rb");
    if (fp == NULL) {
        perror("File opening failed");
        return 1;
    }

    int data[10];
    size_t read = fread(data, sizeof(int), 10, fp);
    
    if (read != 10 && ferror(fp)) {
        perror("Error reading binary data");
        clearerr(fp);
    }

    fclose(fp);
    return 0;
}

此代码从二进制文件中读取一个整数数组。在 fread 之后,我们同时检查返回值和 ferror。这两者结合起来可以确保我们同时检测到 EOF 和实际的读取错误。由于二进制操作的敏感性,它们通常需要这种级别的错误检查。

ferror 与临时文件

临时文件也可能遇到 ferror 可以检测到的错误。

temp_file.c
#include <stdio.h>

int main() {
    FILE *tmp = tmpfile();
    if (tmp == NULL) {
        perror("Temporary file creation failed");
        return 1;
    }

    for (int i = 0; i < 100; i++) {
        fprintf(tmp, "Line %d\n", i);
        
        if (ferror(tmp)) {
            perror("Error writing to temp file");
            clearerr(tmp);
            break;
        }
    }

    fclose(tmp);
    return 0;
}

该程序创建一个临时文件并向其中写入 100 行。每次写入后,ferror 都会检查错误。临时文件可能由于磁盘空间或权限问题而失败。定期的错误检查可确保我们在过程早期就捕获这些问题。

ferror 在网络文件操作中的应用

网络挂载的文件系统可能需要使用 ferror 进行额外的错误检查。

network_file.c
#include <stdio.h>
#include <unistd.h>

int main() {
    FILE *fp = fopen("/mnt/network/share/file.txt", "r");
    if (fp == NULL) {
        perror("Network file opening failed");
        return 1;
    }

    char buffer[256];
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
        
        if (ferror(fp)) {
            perror("Network read error");
            clearerr(fp);
            sleep(1);  // Wait before retrying
        }
    }

    fclose(fp);
    return 0;
}

网络文件可能因连接问题而间歇性失败。此代码从网络文件中读取数据并进行错误检查。当 ferror 检测到问题时,它会等待片刻再继续。这种模式有助于在文件操作中更优雅地处理暂时的网络故障。

ferror 的高级用法与 errno

ferrorerrno 结合使用,以进行详细的错误诊断。

advanced_error.c
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main() {
    FILE *fp = fopen("important.dat", "r+");
    if (fp == NULL) {
        perror("File opening failed");
        return 1;
    }

    // Critical file operation
    if (fseek(fp, 1024, SEEK_SET) != 0 || ferror(fp)) {
        fprintf(stderr, "Seek error: %s\n", strerror(errno));
        clearerr(fp);
    }

    // Data processing would continue here
    fclose(fp);
    return 0;
}

此示例展示了结合使用 ferrorerrno 的高级错误处理。在文件定位操作之后,我们同时检查返回值和 ferrorstrerror 函数提供详细的错误消息。对于需要精确错误信息的关键文件操作,这种方法非常有用。

使用 ferror 的最佳实践

来源

C ferror 文档

本教程演示了 ferror 在健壮的文件处理中的重要性。从基本检查到网络文件场景,正确的错误检测可防止数据损坏并提高可靠性。采用这些技术可以使您的文件操作更具韧性。

作者

我叫 Jan Bodnar,是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我致力于让编程变得易于理解且引人入胜。

列表 C 标准库