C语言文件块读写通过fread()fwrite()函数实现,需以二进制模式(如"wb"或"rb")打开文件,高效处理结构体、数组等批量数据,使用时必须检查函数返回值确保操作成功,并避免未重置文件指针或误用文本模式等常见错误,相比逐字节读写显著提升I/O效率。

C语言中,文件块读写是处理大量数据时高效的操作方式。与逐字节读写相比,块读写能显著提高I/O效率,特别适合处理结构体、数组等数据结构。主要使用fread()fwrite()函数实现。

一、核心函数

1. fread() 函数(文件读取)

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

参数说明:

  • ptr:指向存放读取数据的缓冲区指针
  • size:每个数据块的字节数
  • count:要读取的数据块数量
  • stream:文件指针

返回值:

  • 实际读取的块数(等于count表示成功)
  • 小于count表示可能到达文件末尾或发生错误

2. fwrite() 函数(文件写入)

size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

参数说明:

  • ptr:指向要写入数据的缓冲区指针
  • size:每个数据块的字节数
  • count:要写入的数据块数量
  • stream:文件指针

返回值:

  • 实际写入的块数(等于count表示成功)
  • 小于count表示写入失败

二、使用注意事项

  1. 文件打开方式:建议使用二进制方式打开文件(如"wb+"或"rb+")

    FILE *fp = fopen("data.bin", "wb+"); // 二进制写入
    FILE *fp = fopen("data.bin", "rb");  // 二进制读取
    
  2. 数据存储:文件块读写直接操作字节,不进行格式转换,所以写入的是二进制数据。

  3. 文件指针定位:读取前需将文件指针重置到文件开头

    rewind(fp); // 将文件指针移至文件开头
    

三、使用示例

示例1:结构体数据的块读写

#include <stdio.h>
#include <string.h>

#define N 2

struct Student {
    char name[20];
    int age;
    float score;
};

int main() {
    struct Student students[N];
    FILE *fp;
    
    // 写入数据
    if ((fp = fopen("students.bin", "wb")) == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    // 输入数据
    for (int i = 0; i < N; i++) {
        printf("输入第 %d 个学生信息:\n", i+1);
        printf("姓名: ");
        scanf("%s", students[i].name);
        printf("年龄: ");
        scanf("%d", &students[i].age);
        printf("成绩: ");
        scanf("%f", &students[i].score);
    }
    
    // 块写入文件
    fwrite(students, sizeof(struct Student), N, fp);
    fclose(fp);
    
    // 读取数据
    if ((fp = fopen("students.bin", "rb")) == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    // 重置文件指针
    rewind(fp);
    
    // 块读取数据
    fread(students, sizeof(struct Student), N, fp);
    
    // 显示数据
    printf("\n读取的学生信息:\n");
    for (int i = 0; i < N; i++) {
        printf("姓名: %s, 年龄: %d, 成绩: %.2f\n", 
               students[i].name, students[i].age, students[i].score);
    }
    
    fclose(fp);
    return 0;
}

示例2:数组数据的块读写

#include <stdio.h>

int main() {
    int data[5] = {10, 20, 30, 40, 50};
    FILE *fp;
    
    // 写入数组
    if ((fp = fopen("data.bin", "wb")) == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    fwrite(data, sizeof(int), 5, fp);
    fclose(fp);
    
    // 读取数组
    if ((fp = fopen("data.bin", "rb")) == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    int readData[5];
    fread(readData, sizeof(int), 5, fp);
    
    // 显示读取的数据
    printf("从文件读取的数据: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", readData[i]);
    }
    printf("\n");
    
    fclose(fp);
    return 0;
}

四、重要说明

  1. 文件类型:块读写适合处理二进制文件,如果以文本方式打开文件("w"或"r")进行块读写,会导致数据无法正确读取。

  2. 数据对齐:处理结构体时,需注意内存对齐问题,可能需要使用#pragma pack指定对齐方式。

  3. 错误处理:应检查freadfwrite的返回值,确保数据读写成功:

    if (fread(buffer, size, count, fp) != count) {
        printf("读取失败!\n");
    }
    
  4. 文件结束判断:使用feof()函数判断文件是否结束,但需注意在读取前应先重置文件指针。

五、与逐字节读写的对比

操作方式效率适用场景代码复杂度
字节级读写 (fgetc/fputc)小量文本数据
块读写 (fread/fwrite)大量数据、结构体、数组中高

块读写在处理大量数据时效率更高,特别是当需要处理结构体、数组等复杂数据结构时,是C语言中文件I/O的标准做法。

六、常见错误

  1. 未正确打开文件:忘记使用二进制模式打开文件,导致数据无法正确读写。
  2. 未重置文件指针:写入后直接读取,未使用rewind()重置文件指针。
  3. 未检查返回值:没有检查freadfwrite的返回值,导致错误处理缺失。
  4. 数据类型不匹配:写入的数据类型与读取的类型不一致。

通过正确使用freadfwrite进行文件块读写,可以大大提高C语言程序处理文件的效率,特别适合处理大型数据文件或需要快速I/O的场景。