文件操作

深入理解文件操作

文件操作是C语言中重要的输入输出功能,它允许程序与外部存储设备进行数据交换。东巴文(db-w.cn) 将带你深入理解文件操作的原理与实践。

💡 东巴文观点:文件操作是C语言实现持久化存储的基础,掌握文件操作能够让你的程序保存和处理大量数据。

什么是文件

文件的定义

#include <stdio.h>

void fileDefinition() {
    printf("=== 东巴文文件的定义 ===\n\n");
    
    printf("文件(File):\n");
    printf("  存储在外部介质上的数据集合\n");
    printf("  是程序与外部存储设备交互的桥梁\n");
    printf("  可以长期保存数据\n\n");
    
    printf("文件的分类:\n");
    printf("  1. 文本文件:以ASCII码形式存储\n");
    printf("  2. 二进制文件:以二进制形式存储\n");
    printf("  3. 顺序文件:按顺序读写\n");
    printf("  4. 随机文件:可随机访问\n");
}

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

文件指针

#include <stdio.h>

void filePointer() {
    printf("=== 东巴文文件指针 ===\n\n");
    
    printf("文件指针(FILE *):\n");
    printf("  指向FILE结构体的指针\n");
    printf("  用于标识和操作文件\n");
    printf("  包含文件的状态信息\n\n");
    
    printf("FILE结构体包含:\n");
    printf("  1. 文件描述符\n");
    printf("  2. 缓冲区位置\n");
    printf("  3. 缓冲区大小\n");
    printf("  4. 当前读写位置\n");
    printf("  5. 文件状态标志\n");
}

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

文件的打开与关闭

打开文件

#include <stdio.h>

void openFile() {
    printf("=== 东巴文打开文件 ===\n\n");
    
    // 打开文件
    FILE *fp = fopen("example.txt", "w");
    
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    printf("文件打开成功\n");
    
    // 关闭文件
    fclose(fp);
    printf("文件已关闭\n");
    
    printf("\n打开模式:\n");
    printf("  \"r\" - 只读(文件必须存在)\n");
    printf("  \"w\" - 只写(文件不存在则创建,存在则清空)\n");
    printf("  \"a\" - 追加(文件不存在则创建)\n");
    printf("  \"r+\" - 读写(文件必须存在)\n");
    printf("  \"w+\" - 读写(文件不存在则创建,存在则清空)\n");
    printf("  \"a+\" - 读写追加(文件不存在则创建)\n");
    printf("  \"rb\" - 二进制只读\n");
    printf("  \"wb\" - 二进制只写\n");
    printf("  \"ab\" - 二进制追加\n");
}

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

关闭文件

#include <stdio.h>

void closeFile() {
    printf("=== 东巴文关闭文件 ===\n\n");
    
    FILE *fp = fopen("test.txt", "w");
    
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    printf("文件打开成功\n");
    
    // 关闭文件
    int result = fclose(fp);
    
    if (result == 0) {
        printf("文件关闭成功\n");
    } else {
        printf("文件关闭失败\n");
    }
    
    printf("\n关闭文件的作用:\n");
    printf("  1. 刷新缓冲区\n");
    printf("  2. 释放文件指针\n");
    printf("  3. 释放系统资源\n");
}

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

文件的读写

字符读写

#include <stdio.h>

void characterIO() {
    printf("=== 东巴文字符读写 ===\n\n");
    
    // 写入字符
    FILE *fp = fopen("char.txt", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fputc('东', fp);
    fputc('巴', fp);
    fputc('文', fp);
    fputc('\n', fp);
    
    fclose(fp);
    printf("字符写入成功\n");
    
    // 读取字符
    fp = fopen("char.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    printf("读取的内容:");
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    
    fclose(fp);
    
    printf("\n字符读写函数:\n");
    printf("  fputc(ch, fp) - 写入一个字符\n");
    printf("  fgetc(fp) - 读取一个字符\n");
    printf("  putchar(ch) - 输出一个字符\n");
}

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

字符串读写

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

void stringIO() {
    printf("=== 东巴文字符串读写 ===\n\n");
    
    // 写入字符串
    FILE *fp = fopen("string.txt", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fputs("东巴文\n", fp);
    fputs("db-w.cn\n", fp);
    fputs("C语言教程\n", fp);
    
    fclose(fp);
    printf("字符串写入成功\n");
    
    // 读取字符串
    fp = fopen("string.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    char buffer[100];
    printf("读取的内容:\n");
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("  %s", buffer);
    }
    
    fclose(fp);
    
    printf("\n字符串读写函数:\n");
    printf("  fputs(str, fp) - 写入一个字符串\n");
    printf("  fgets(buf, n, fp) - 读取一行字符串\n");
}

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

格式化读写

#include <stdio.h>

void formattedIO() {
    printf("=== 东巴文格式化读写 ===\n\n");
    
    // 写入格式化数据
    FILE *fp = fopen("formatted.txt", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fprintf(fp, "姓名:%s\n", "东巴文");
    fprintf(fp, "年龄:%d\n", 20);
    fprintf(fp, "成绩:%.1f\n", 95.5);
    
    fclose(fp);
    printf("格式化数据写入成功\n");
    
    // 读取格式化数据
    fp = fopen("formatted.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    char name[50];
    int age;
    float score;
    
    fscanf(fp, "姓名:%s\n", name);
    fscanf(fp, "年龄:%d\n", &age);
    fscanf(fp, "成绩:%f\n", &score);
    
    fclose(fp);
    
    printf("读取的数据:\n");
    printf("  姓名:%s\n", name);
    printf("  年龄:%d\n", age);
    printf("  成绩:%.1f\n", score);
    
    printf("\n格式化读写函数:\n");
    printf("  fprintf(fp, format, ...) - 格式化写入\n");
    printf("  fscanf(fp, format, ...) - 格式化读取\n");
}

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

二进制读写

#include <stdio.h>

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

void binaryIO() {
    printf("=== 东巴文二进制读写 ===\n\n");
    
    // 写入二进制数据
    FILE *fp = fopen("student.dat", "wb");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    Student students[3] = {
        {"张三", 20, 85.5},
        {"李四", 21, 90.0},
        {"王五", 22, 88.5}
    };
    
    fwrite(students, sizeof(Student), 3, fp);
    fclose(fp);
    printf("二进制数据写入成功\n");
    
    // 读取二进制数据
    fp = fopen("student.dat", "rb");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    Student readStudents[3];
    fread(readStudents, sizeof(Student), 3, fp);
    fclose(fp);
    
    printf("读取的数据:\n");
    for (int i = 0; i < 3; i++) {
        printf("  学生%d: %s, %d岁, 成绩%.1f\n", 
               i + 1, readStudents[i].name, 
               readStudents[i].age, readStudents[i].score);
    }
    
    printf("\n二进制读写函数:\n");
    printf("  fwrite(ptr, size, n, fp) - 写入二进制数据\n");
    printf("  fread(ptr, size, n, fp) - 读取二进制数据\n");
}

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

文件的定位

获取当前位置

#include <stdio.h>

void getPosition() {
    printf("=== 东巴文获取当前位置 ===\n\n");
    
    FILE *fp = fopen("position.txt", "w+");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fprintf(fp, "东巴文db-w.cn");
    
    // 获取当前位置
    long pos = ftell(fp);
    printf("当前位置:%ld\n", pos);
    
    fclose(fp);
    
    printf("\n位置函数:\n");
    printf("  ftell(fp) - 获取当前读写位置\n");
}

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

设置位置

#include <stdio.h>

void setPosition() {
    printf("=== 东巴文设置位置 ===\n\n");
    
    FILE *fp = fopen("seek.txt", "w+");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fprintf(fp, "0123456789");
    
    // 移动到文件开头
    rewind(fp);
    printf("移动到开头\n");
    
    // 从当前位置向后移动3个字节
    fseek(fp, 3, SEEK_CUR);
    printf("当前位置:%ld\n", ftell(fp));
    
    // 从文件末尾向前移动5个字节
    fseek(fp, -5, SEEK_END);
    printf("当前位置:%ld\n", ftell(fp));
    
    // 从文件开头移动到第5个字节
    fseek(fp, 5, SEEK_SET);
    printf("当前位置:%ld\n", ftell(fp));
    
    fclose(fp);
    
    printf("\n定位函数:\n");
    printf("  fseek(fp, offset, origin) - 设置读写位置\n");
    printf("    SEEK_SET - 文件开头\n");
    printf("    SEEK_CUR - 当前位置\n");
    printf("    SEEK_END - 文件末尾\n");
    printf("  rewind(fp) - 移动到文件开头\n");
}

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

文件的错误处理

错误检测

#include <stdio.h>

void errorDetection() {
    printf("=== 东巴文错误检测 ===\n\n");
    
    FILE *fp = fopen("nonexistent.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        printf("错误信息:%s\n", strerror(errno));
        return;
    }
    
    // 检测文件错误
    if (ferror(fp)) {
        printf("文件操作发生错误\n");
        clearerr(fp);  // 清除错误标志
    }
    
    // 检测文件结束
    if (feof(fp)) {
        printf("已到达文件末尾\n");
    }
    
    fclose(fp);
    
    printf("\n错误处理函数:\n");
    printf("  ferror(fp) - 检测文件错误\n");
    printf("  feof(fp) - 检测文件结束\n");
    printf("  clearerr(fp) - 清除错误标志\n");
    printf("  perror(str) - 输出错误信息\n");
}

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

文件操作实例

1. 文件复制

#include <stdio.h>

void fileCopy() {
    printf("=== 东巴文文件复制 ===\n\n");
    
    FILE *src = fopen("source.txt", "r");
    FILE *dst = fopen("dest.txt", "w");
    
    if (src == NULL || dst == NULL) {
        printf("文件打开失败\n");
        if (src) fclose(src);
        if (dst) fclose(dst);
        return;
    }
    
    int ch;
    while ((ch = fgetc(src)) != EOF) {
        fputc(ch, dst);
    }
    
    fclose(src);
    fclose(dst);
    
    printf("文件复制成功\n");
}

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

2. 文件统计

#include <stdio.h>

void fileStatistics() {
    printf("=== 东巴文文件统计 ===\n\n");
    
    FILE *fp = fopen("statistics.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    int chars = 0, words = 0, lines = 0;
    int ch, inWord = 0;
    
    while ((ch = fgetc(fp)) != EOF) {
        chars++;
        
        if (ch == '\n') {
            lines++;
        }
        
        if (ch == ' ' || ch == '\n' || ch == '\t') {
            inWord = 0;
        } else if (inWord == 0) {
            inWord = 1;
            words++;
        }
    }
    
    fclose(fp);
    
    printf("文件统计:\n");
    printf("  字符数:%d\n", chars);
    printf("  单词数:%d\n", words);
    printf("  行数:%d\n", lines);
}

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

3. 配置文件读写

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

typedef struct {
    char key[50];
    char value[100];
} Config;

void writeConfig() {
    printf("=== 东巴文写配置文件 ===\n\n");
    
    FILE *fp = fopen("config.ini", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    fprintf(fp, "# 东巴文配置文件\n");
    fprintf(fp, "name=东巴文\n");
    fprintf(fp, "version=1.0\n");
    fprintf(fp, "author=db-w.cn\n");
    
    fclose(fp);
    printf("配置文件写入成功\n");
}

void readConfig() {
    printf("\n=== 东巴文读配置文件 ===\n\n");
    
    FILE *fp = fopen("config.ini", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    char line[200];
    while (fgets(line, sizeof(line), fp) != NULL) {
        // 跳过注释行
        if (line[0] == '#' || line[0] == '\n') {
            continue;
        }
        
        // 解析键值对
        char *equals = strchr(line, '=');
        if (equals != NULL) {
            *equals = '\0';
            char *key = line;
            char *value = equals + 1;
            
            // 去除换行符
            char *newline = strchr(value, '\n');
            if (newline != NULL) {
                *newline = '\0';
            }
            
            printf("  %s = %s\n", key, value);
        }
    }
    
    fclose(fp);
}

int main() {
    writeConfig();
    readConfig();
    return 0;
}

东巴文最佳实践

1. 检查文件操作返回值

#include <stdio.h>

void checkReturnValue() {
    printf("=== 东巴文检查返回值 ===\n\n");
    
    FILE *fp = fopen("test.txt", "r");
    
    // ✅ 好的做法:检查返回值
    if (fp == NULL) {
        printf("文件打开失败:%s\n", strerror(errno));
        return;
    }
    
    // ❌ 不好的做法:不检查返回值
    // FILE *fp = fopen("test.txt", "r");
    // fprintf(fp, "data");  // 可能崩溃
    
    fclose(fp);
    
    printf("检查返回值的重要性:\n");
    printf("  1. 避免程序崩溃\n");
    printf("  2. 提供错误信息\n");
    printf("  3. 提高程序健壮性\n");
}

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

2. 及时关闭文件

#include <stdio.h>

void closeFileTimely() {
    printf("=== 东巴文及时关闭文件 ===\n\n");
    
    // ✅ 好的做法:及时关闭
    {
        FILE *fp = fopen("test.txt", "w");
        if (fp != NULL) {
            fprintf(fp, "东巴文");
            fclose(fp);  // 使用完毕立即关闭
        }
    }
    
    // ❌ 不好的做法:延迟关闭
    // FILE *fp = fopen("test.txt", "w");
    // ... 很多代码
    // fclose(fp);  // 可能忘记关闭
    
    printf("及时关闭文件的好处:\n");
    printf("  1. 释放系统资源\n");
    printf("  2. 刷新缓冲区\n");
    printf("  3. 避免资源泄漏\n");
}

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

3. 使用缓冲区

#include <stdio.h>

void useBuffer() {
    printf("=== 东巴文使用缓冲区 ===\n\n");
    
    FILE *fp = fopen("buffer.txt", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }
    
    // 设置缓冲区
    char buffer[4096];
    setvbuf(fp, buffer, _IOFBF, sizeof(buffer));
    
    // 写入数据
    for (int i = 0; i < 1000; i++) {
        fprintf(fp, "东巴文%d\n", i);
    }
    
    fclose(fp);
    
    printf("缓冲区设置成功\n");
    
    printf("\n缓冲区类型:\n");
    printf("  _IOFBF - 全缓冲\n");
    printf("  _IOLBF - 行缓冲\n");
    printf("  _IONBF - 无缓冲\n");
}

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

东巴文验证清单

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

  • 理解文件的定义
  • 掌握文件指针
  • 掌握文件的打开与关闭
  • 掌握文件的读写操作
  • 掌握文件的定位
  • 掌握文件的错误处理
  • 掌握文件操作实例
  • 掌握最佳实践

下一步学习

掌握文件操作后,你可以继续学习:

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


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

🎯 东巴文文件操作提示:文件操作是C语言实现持久化存储的基础。在 db-w.cn,我们会通过大量实例帮你掌握文件操作!