文件的顺序读写

深入理解文件顺序读写

文件顺序读写是C语言中最常用的文件操作方式。东巴文(db-w.cn) 将带你深入理解文件顺序读写的原理与实践。

💡 东巴文观点:顺序读写是文件操作的基础,掌握顺序读写能够让你处理大多数文件操作需求。

什么是顺序读写

顺序读写的定义

#include <stdio.h>

void sequentialIODefinition() {
    printf("=== 东巴文顺序读写的定义 ===\n\n");
    
    printf("顺序读写(Sequential I/O):\n");
    printf("  按照文件的字节顺序依次读写\n");
    printf("  文件位置指针自动移动\n");
    printf("  是最常用的文件操作方式\n\n");
    
    printf("顺序读写特点:\n");
    printf("  1. 简单易用\n");
    printf("  2. 效率较高\n");
    printf("  3. 适合处理整个文件\n");
    printf("  4. 文件位置自动管理\n");
    
    printf("\n顺序读写分类:\n");
    printf("  1. 字符读写:fgetc, fputc\n");
    printf("  2. 字符串读写:fgets, fputs\n");
    printf("  3. 格式化读写:fscanf, fprintf\n");
    printf("  4. 二进制读写:fread, fwrite\n");
}

int main() {
    sequentialIODefinition();
    return 0;
}

字符读写

fputc函数

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

void fputcFunction() {
    printf("=== 东巴文fputc函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  int fputc(int ch, FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  向文件写入一个字符\n\n");
    
    printf("参数:\n");
    printf("  ch     - 要写入的字符\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功:写入的字符\n");
    printf("  失败:EOF\n");
    
    // 示例
    FILE *fp = fopen("char.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 写入字符
    fputc('东', fp);
    fputc('巴', fp);
    fputc('文', fp);
    fputc('\n', fp);
    
    fclose(fp);
    printf("\n字符写入成功\n");
}

int main() {
    fputcFunction();
    return 0;
}

fgetc函数

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

void fgetcFunction() {
    printf("=== 东巴文fgetc函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  int fgetc(FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  从文件读取一个字符\n\n");
    
    printf("参数:\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功:读取的字符\n");
    printf("  失败或EOF:EOF\n");
    
    // 示例:先创建文件
    FILE *fp = fopen("char.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "东巴文\n");
        fclose(fp);
    }
    
    // 读取字符
    fp = fopen("char.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    printf("读取字符:");
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    
    fclose(fp);
}

int main() {
    fgetcFunction();
    return 0;
}

字符读写实例

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

void characterIOExample() {
    printf("=== 东巴文字符读写实例 ===\n\n");
    
    // 写入字符
    FILE *fp = fopen("letter.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 写入A-Z
    for (char ch = 'A'; ch <= 'Z'; ch++) {
        fputc(ch, fp);
    }
    fputc('\n', fp);
    
    fclose(fp);
    printf("字母写入成功\n");
    
    // 读取字符
    fp = fopen("letter.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    printf("读取字母:");
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    
    fclose(fp);
    
    printf("\n字符读写应用:\n");
    printf("  1. 复制文件\n");
    printf("  2. 字符统计\n");
    printf("  3. 字符转换\n");
    printf("  4. 文本处理\n");
}

int main() {
    characterIOExample();
    return 0;
}

字符串读写

fputs函数

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

void fputsFunction() {
    printf("=== 东巴文fputs函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  int fputs(const char* str, FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  向文件写入一个字符串\n\n");
    
    printf("参数:\n");
    printf("  str    - 要写入的字符串\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功:非负数\n");
    printf("  失败:EOF\n");
    
    // 示例
    FILE *fp = fopen("string.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 写入字符串
    fputs("东巴文db-w.cn\n", fp);
    fputs("字符串写入示例\n", fp);
    fputs("第三行内容\n", fp);
    
    fclose(fp);
    printf("\n字符串写入成功\n");
}

int main() {
    fputsFunction();
    return 0;
}

fgets函数

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

void fgetsFunction() {
    printf("=== 东巴文fgets函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  char* fgets(char* str, int n, FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  从文件读取一行字符串\n\n");
    
    printf("参数:\n");
    printf("  str    - 存储读取的字符串\n");
    printf("  n      - 最大读取字符数\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功:str指针\n");
    printf("  失败或EOF:NULL\n");
    
    printf("\n注意事项:\n");
    printf("  1. 读取n-1个字符或遇到换行符\n");
    printf("  2. 保留换行符\n");
    printf("  3. 自动添加字符串结束符\n");
    
    // 示例:先创建文件
    FILE *fp = fopen("string.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "第一行\n");
        fprintf(fp, "第二行\n");
        fprintf(fp, "第三行\n");
        fclose(fp);
    }
    
    // 读取字符串
    fp = fopen("string.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    char buffer[100];
    printf("\n读取内容:\n");
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("  %s", buffer);
    }
    
    fclose(fp);
}

int main() {
    fgetsFunction();
    return 0;
}

字符串读写实例

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

void stringIOExample() {
    printf("=== 东巴文字符串读写实例 ===\n\n");
    
    // 写入多行文本
    FILE *fp = fopen("poem.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    const char *lines[] = {
        "东巴文db-w.cn",
        "编程学习平台",
        "让学习更简单",
        "让编程更有趣"
    };
    
    for (int i = 0; i < 4; i++) {
        fputs(lines[i], fp);
        fputc('\n', fp);
    }
    
    fclose(fp);
    printf("诗歌写入成功\n");
    
    // 读取并显示
    fp = fopen("poem.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    printf("\n诗歌内容:\n");
    printf("---\n");
    
    char buffer[100];
    int lineNum = 1;
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        // 移除换行符
        buffer[strcspn(buffer, "\n")] = '\0';
        printf("%d. %s\n", lineNum++, buffer);
    }
    
    printf("---\n");
    
    fclose(fp);
    
    printf("\n字符串读写应用:\n");
    printf("  1. 配置文件处理\n");
    printf("  2. 日志文件记录\n");
    printf("  3. 文本文件编辑\n");
    printf("  4. 数据导入导出\n");
}

int main() {
    stringIOExample();
    return 0;
}

格式化读写

fprintf函数

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

void fprintfFunction() {
    printf("=== 东巴文fprintf函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  int fprintf(FILE* stream, const char* format, ...);\n\n");
    
    printf("功能:\n");
    printf("  格式化输出到文件\n\n");
    
    printf("参数:\n");
    printf("  stream - 文件指针\n");
    printf("  format - 格式字符串\n");
    printf("  ...    - 可变参数\n\n");
    
    printf("返回值:\n");
    printf("  成功:写入的字符数\n");
    printf("  失败:负数\n");
    
    // 示例
    FILE *fp = fopen("data.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 格式化写入
    fprintf(fp, "姓名:%s\n", "东巴文");
    fprintf(fp, "年龄:%d\n", 20);
    fprintf(fp, "成绩:%.2f\n", 95.5);
    fprintf(fp, "日期:%04d-%02d-%02d\n", 2024, 1, 15);
    
    fclose(fp);
    printf("\n格式化数据写入成功\n");
}

int main() {
    fprintfFunction();
    return 0;
}

fscanf函数

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

void fscanfFunction() {
    printf("=== 东巴文fscanf函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  int fscanf(FILE* stream, const char* format, ...);\n\n");
    
    printf("功能:\n");
    printf("  从文件格式化输入\n\n");
    
    printf("参数:\n");
    printf("  stream - 文件指针\n");
    printf("  format - 格式字符串\n");
    printf("  ...    - 可变参数指针\n\n");
    
    printf("返回值:\n");
    printf("  成功:读取的项目数\n");
    printf("  失败或EOF:EOF\n");
    
    // 示例:先创建文件
    FILE *fp = fopen("data.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "东巴文 20 95.5\n");
        fprintf(fp, "张三 21 88.0\n");
        fprintf(fp, "李四 22 92.5\n");
        fclose(fp);
    }
    
    // 格式化读取
    fp = fopen("data.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    printf("\n读取数据:\n");
    char name[50];
    int age;
    float score;
    
    while (fscanf(fp, "%s %d %f", name, &age, &score) == 3) {
        printf("  姓名:%s, 年龄:%d, 成绩:%.1f\n", name, age, score);
    }
    
    fclose(fp);
}

int main() {
    fscanfFunction();
    return 0;
}

格式化读写实例

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

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

void formattedIOExample() {
    printf("=== 东巴文格式化读写实例 ===\n\n");
    
    // 写入学生数据
    FILE *fp = fopen("students.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    Student students[3] = {
        {"东巴文", 20, 95.5f},
        {"张三", 21, 88.0f},
        {"李四", 22, 92.5f}
    };
    
    for (int i = 0; i < 3; i++) {
        fprintf(fp, "%s %d %.2f\n", 
                students[i].name, 
                students[i].age, 
                students[i].score);
    }
    
    fclose(fp);
    printf("学生数据写入成功\n");
    
    // 读取学生数据
    fp = fopen("students.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    printf("\n读取学生数据:\n");
    Student student;
    while (fscanf(fp, "%s %d %f", 
                  student.name, 
                  &student.age, 
                  &student.score) == 3) {
        printf("  %s, %d岁, 成绩%.1f\n", 
               student.name, student.age, student.score);
    }
    
    fclose(fp);
    
    printf("\n格式化读写应用:\n");
    printf("  1. 结构化数据存储\n");
    printf("  2. 配置文件读写\n");
    printf("  3. 数据报表生成\n");
    printf("  4. 日志记录\n");
}

int main() {
    formattedIOExample();
    return 0;
}

二进制读写

fwrite函数

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

void fwriteFunction() {
    printf("=== 东巴文fwrite函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  size_t fwrite(const void* ptr, size_t size, size_t n, FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  写入二进制数据块\n\n");
    
    printf("参数:\n");
    printf("  ptr    - 数据指针\n");
    printf("  size   - 每个元素的大小\n");
    printf("  n      - 元素个数\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功写入的元素个数\n");
    
    // 示例
    FILE *fp = fopen("binary.dat", "wb");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    int numbers[] = {1, 2, 3, 4, 5};
    size_t count = fwrite(numbers, sizeof(int), 5, fp);
    
    fclose(fp);
    printf("\n写入 %zu 个整数\n", count);
}

int main() {
    fwriteFunction();
    return 0;
}

fread函数

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

void freadFunction() {
    printf("=== 东巴文fread函数 ===\n\n");
    
    printf("函数原型:\n");
    printf("  size_t fread(void* ptr, size_t size, size_t n, FILE* stream);\n\n");
    
    printf("功能:\n");
    printf("  读取二进制数据块\n\n");
    
    printf("参数:\n");
    printf("  ptr    - 存储数据的指针\n");
    printf("  size   - 每个元素的大小\n");
    printf("  n      - 元素个数\n");
    printf("  stream - 文件指针\n\n");
    
    printf("返回值:\n");
    printf("  成功读取的元素个数\n");
    
    // 示例:先创建文件
    FILE *fp = fopen("binary.dat", "wb");
    if (fp != NULL) {
        int nums[] = {10, 20, 30, 40, 50};
        fwrite(nums, sizeof(int), 5, fp);
        fclose(fp);
    }
    
    // 读取数据
    fp = fopen("binary.dat", "rb");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    int numbers[5];
    size_t count = fread(numbers, sizeof(int), 5, fp);
    
    printf("\n读取 %zu 个整数:\n", count);
    for (size_t i = 0; i < count; i++) {
        printf("  numbers[%zu] = %d\n", i, numbers[i]);
    }
    
    fclose(fp);
}

int main() {
    freadFunction();
    return 0;
}

二进制读写实例

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

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

void binaryIOExample() {
    printf("=== 东巴文二进制读写实例 ===\n\n");
    
    // 写入结构体数组
    FILE *fp = fopen("students.dat", "wb");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    Student students[3] = {
        {"东巴文", 20, 95.5f},
        {"张三", 21, 88.0f},
        {"李四", 22, 92.5f}
    };
    
    size_t written = fwrite(students, sizeof(Student), 3, fp);
    fclose(fp);
    
    printf("写入 %zu 条学生记录\n", written);
    
    // 读取结构体数组
    fp = fopen("students.dat", "rb");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    Student readStudents[3];
    size_t count = fread(readStudents, sizeof(Student), 3, fp);
    
    printf("\n读取 %zu 条学生记录:\n", count);
    for (size_t i = 0; i < count; i++) {
        printf("  %s, %d岁, 成绩%.1f\n", 
               readStudents[i].name, 
               readStudents[i].age, 
               readStudents[i].score);
    }
    
    fclose(fp);
    
    printf("\n二进制读写优势:\n");
    printf("  1. 读写速度快\n");
    printf("  2. 占用空间小\n");
    printf("  3. 适合大量数据\n");
    printf("  4. 保持数据精度\n");
}

int main() {
    binaryIOExample();
    return 0;
}

东巴文最佳实践

1. 选择合适的读写方式

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

void chooseRightMethod() {
    printf("=== 东巴文选择合适的读写方式 ===\n\n");
    
    printf("读写方式选择:\n\n");
    
    printf("1. 字符读写(fgetc/fputc):\n");
    printf("   适用:逐字符处理\n");
    printf("   场景:字符统计、字符转换\n\n");
    
    printf("2. 字符串读写(fgets/fputs):\n");
    printf("   适用:逐行处理\n");
    printf("   场景:文本文件、配置文件\n\n");
    
    printf("3. 格式化读写(fscanf/fprintf):\n");
    printf("   适用:结构化文本数据\n");
    printf("   场景:数据报表、日志文件\n\n");
    
    printf("4. 二进制读写(fread/fwrite):\n");
    printf("   适用:二进制数据、结构体\n");
    printf("   场景:数据库、图像、音频\n");
    
    printf("\n选择建议:\n");
    printf("  1. 文本文件:字符串或格式化读写\n");
    printf("  2. 二进制文件:二进制读写\n");
    printf("  3. 需要可读性:格式化读写\n");
    printf("  4. 需要效率:二进制读写\n");
}

int main() {
    chooseRightMethod();
    return 0;
}

2. 检查读写结果

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

void checkIOResult() {
    printf("=== 东巴文检查读写结果 ===\n\n");
    
    FILE *fp = fopen("test.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 检查写入结果
    int result = fprintf(fp, "东巴文db-w.cn\n");
    if (result < 0) {
        perror("写入失败");
        fclose(fp);
        return;
    }
    printf("写入 %d 个字符\n", result);
    
    // 检查关闭结果
    if (fclose(fp) != 0) {
        perror("关闭文件失败");
        return;
    }
    
    printf("文件操作成功\n");
    
    printf("\n检查建议:\n");
    printf("  1. 检查fopen返回值\n");
    printf("  2. 检查fprintf/fwrite返回值\n");
    printf("  3. 检查fscanf/fread返回值\n");
    printf("  4. 检查fclose返回值\n");
}

int main() {
    checkIOResult();
    return 0;
}

3. 处理文件结束

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

void handleFileEnd() {
    printf("=== 东巴文处理文件结束 ===\n\n");
    
    // 创建测试文件
    FILE *fp = fopen("test.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "第一行\n第二行\n第三行\n");
        fclose(fp);
    }
    
    // 方法1:检查fgets返回值
    printf("方法1:检查fgets返回值\n");
    fp = fopen("test.txt", "r");
    if (fp != NULL) {
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("  %s", buffer);
        }
        fclose(fp);
    }
    
    // 方法2:检查fscanf返回值
    printf("\n方法2:检查fscanf返回值\n");
    fp = fopen("test.txt", "r");
    if (fp != NULL) {
        char line[100];
        while (fscanf(fp, "%s", line) == 1) {
            printf("  %s\n", line);
        }
        fclose(fp);
    }
    
    // 方法3:使用feof(不推荐)
    printf("\n方法3:使用feof(不推荐)\n");
    fp = fopen("test.txt", "r");
    if (fp != NULL) {
        char buffer[100];
        while (!feof(fp)) {
            if (fgets(buffer, sizeof(buffer), fp) != NULL) {
                printf("  %s", buffer);
            }
        }
        fclose(fp);
    }
    
    printf("\n处理建议:\n");
    printf("  1. 优先检查读写函数返回值\n");
    printf("  2. 避免单独使用feof\n");
    printf("  3. 正确处理EOF\n");
    printf("  4. 注意最后一次读取\n");
}

int main() {
    handleFileEnd();
    return 0;
}

4. 使用缓冲区

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

void useBuffer() {
    printf("=== 东巴文使用缓冲区 ===\n\n");
    
    printf("缓冲区的作用:\n");
    printf("  1. 减少磁盘I/O次数\n");
    printf("  2. 提高读写效率\n");
    printf("  3. 批量处理数据\n\n");
    
    // 创建大文件
    FILE *fp = fopen("large.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    // 使用缓冲区写入
    char buffer[4096];
    memset(buffer, 'A', sizeof(buffer) - 1);
    buffer[sizeof(buffer) - 1] = '\0';
    
    for (int i = 0; i < 100; i++) {
        fprintf(fp, "%s\n", buffer);
    }
    
    fclose(fp);
    printf("大文件创建成功\n");
    
    // 使用缓冲区读取
    fp = fopen("large.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return;
    }
    
    size_t totalLines = 0;
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        totalLines++;
    }
    
    fclose(fp);
    printf("读取 %zu 行\n", totalLines);
    
    printf("\n缓冲区建议:\n");
    printf("  1. 使用适当大小的缓冲区\n");
    printf("  2. 批量读写数据\n");
    printf("  3. 避免频繁的小量读写\n");
    printf("  4. 考虑使用setvbuf\n");
}

int main() {
    useBuffer();
    return 0;
}

东巴文验证清单

完成本章学习后,请确认:

  • 理解顺序读写的概念
  • 掌握字符读写函数
  • 掌握字符串读写函数
  • 掌握格式化读写函数
  • 掌握二进制读写函数
  • 掌握最佳实践

下一步学习

掌握文件顺序读写后,你可以继续学习:

如果遇到问题,欢迎访问 东巴文(db-w.cn) 获取帮助!


东巴文(db-w.cn) - 让编程学习更简单

🎯 东巴文顺序读写提示:顺序读写是文件操作的基础。在 db-w.cn,我们会通过大量实例帮你掌握文件操作!