文件操作:二进制读写

二进制读写

1. 文本文件与二进制文件的区别

文本文件和二进制文件在存储格式、读写方式和适用场景上存在本质区别:

存储格式不同:

  • 文本文件:只能存储文本数据(ASCII或Unicode字符),每个字符对应一个字节或多个字节
  • 二进制文件:可以存储任何类型的数据,包括整数、浮点数、结构体、图像、音频等原始数据

读写方式不同:

  • 文本文件使用格式化I/O函数(如fprintffscanf
  • 二进制文件使用原始I/O函数(如freadfwrite

换行符处理不同:

  • 文本文件在不同操作系统中的换行符会自动转换(Windows: \r\n,Linux: \n
  • 二进制文件不进行任何转换,按原样读写

2. 二进制读写函数详解

2.1 fwrite函数
c 复制代码
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);

参数说明:

  • ptr:指向要写入数据的指针
  • size:每个数据项的大小(字节)
  • n:要写入的数据项数量
  • fp:文件指针

返回值: 成功写入的数据项数量

2.2 fread函数
c 复制代码
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);

参数说明:

  • ptr:指向存储读取数据的缓冲区指针
  • size:每个数据项的大小(字节)
  • n:要读取的数据项数量
  • fp:文件指针

返回值: 成功读取的数据项数量

3. 实践示例

示例1:写入和读取整数数组
c 复制代码
#include <stdio.h>

int main() {
    // 写入二进制数据
    int numbers[] = {10, 20, 30, 40, 50};
    FILE *fp = fopen("data.bin", "wb");
    
    if (fp == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    // 写入整个数组
    size_t written = fwrite(numbers, sizeof(int), 5, fp);
    printf("成功写入 %zu 个整数\n", written);
    fclose(fp);
    
    // 读取二进制数据
    int read_numbers[5];
    fp = fopen("data.bin", "rb");
    
    if (fp == NULL) {
        printf("文件打开失败!\n");
        return 1;
    }
    
    size_t read = fread(read_numbers, sizeof(int), 5, fp);
    printf("成功读取 %zu 个整数:", read);
    
    for (int i = 0; i < read; i++) {
        printf("%d ", read_numbers[i]);
    }
    printf("\n");
    
    fclose(fp);
    return 0;
}
示例2:写入和读取结构体
c 复制代码
#include <stdio.h>
#include <string.h>

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

int main() {
    Student stu1 = {1001, "张三", 85.5};
    Student stu2 = {1002, "李四", 92.0};
    
    // 写入结构体
    FILE *fp = fopen("students.bin", "wb");
    if (fp) {
        fwrite(&stu1, sizeof(Student), 1, fp);
        fwrite(&stu2, sizeof(Student), 1, fp);
        fclose(fp);
    }
    
    // 读取结构体
    Student stu_read;
    fp = fopen("students.bin", "rb");
    if (fp) {
        printf("学生信息:\n");
        while (fread(&stu_read, sizeof(Student), 1, fp) == 1) {
            printf("ID: %d, 姓名: %s, 分数: %.1f\n", 
                   stu_read.id, stu_read.name, stu_read.score);
        }
        fclose(fp);
    }
    
    return 0;
}

4. 二进制文件操作的最佳实践

  1. 检查返回值 :始终检查freadfwrite的返回值,确保读写操作成功
  2. 使用正确的打开模式
    • "rb":以二进制只读方式打开
    • "wb":以二进制只写方式打开(会清空文件)
    • "ab":以二进制追加方式打开
    • "rb+":以二进制读写方式打开
  3. 处理文件大小 :使用fseekftell获取文件大小,避免读取超出文件范围
  4. 内存对齐 :结构体成员可能需要内存对齐,使用#pragma pack或编译器选项控制

5. 性能对比

操作类型 文本文件 二进制文件
写入速度 较慢(需要格式化) 较快(直接内存拷贝)
读取速度 较慢(需要解析) 较快(直接加载到内存)
文件大小 较大 较小
可读性
跨平台 需要处理换行符 需要处理字节序