跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C

Linux 基础 IO 系列(二):C 语言标准库 IO 接口实战

系统讲解了 C 语言标准库 IO 的核心接口,包括 fopen、fclose、fread、fwrite 及 feof 函数的用法与参数细节。文章对比了 6 种文件打开模式,介绍了 stdin、stdout、stderr 三个默认流,并提供了 errno、perror 等错误处理技巧。通过实现简化版 cat 命令和文件拷贝工具,帮助开发者掌握跨平台文件操作的规范与原理。

随缘发布于 2026/3/30更新于 2026/7/1151 浏览
Linux 基础 IO 系列(二):C 语言标准库 IO 接口实战

7c5cb530801fd2a96387ec30de69e081.jpg

在学具体接口前,我们得先明白一个核心问题:操作系统已经提供了 open/read/write 等系统调用,为什么还要 C 库 IO(fopen/fread/fwrite)?

答案有两个:

  1. 封装复杂逻辑,降低开发难度:系统调用需要处理很多底层细节(比如文件描述符管理、权限校验),C 库 IO 把这些细节 '包起来',提供更简单的接口。比如用 fopen("test.txt", "r") 就能打开文件,不用关心底层 open 函数的 flags 位标志位、mode 权限位。
  2. 保证跨平台兼容性:不同操作系统的系统调用不一样(比如 Linux 的 open 和 Windows 的 CreateFile),但 C 库 IO 是 '标准接口'—— 只要你的代码用的是 fopen/fread,在 Linux、Windows、macOS 上都能跑(前提是不依赖系统特有功能)。

简单说,C 库 IO 是 '用户友好型中间商':它封装了系统调用,给我们提供简单、通用的文件操作方式。

一、核心接口拆解:从打开到关闭的全流程

C 语言标准库提供了一套完整的文件操作接口,核心是 '打开→读写→判断结束→关闭' 的流程。我们逐个拆解每个接口的用法、参数细节和注意事项。

1. 第一步:打开文件 —— fopen

要操作文件,第一步必须 '打开文件'—— 用 fopen 函数建立程序与文件的关联,就像 '打开房门才能进房间'。

1. 函数语法
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
2. 参数解析
参数名含义示例
filename要打开的文件路径(相对路径 / 绝对路径)"test.txt"(当前目录)、"/home/user/log.txt"(绝对路径)
mode打开模式(决定文件可读写性、是否创建、是否追加等)"r"(只读)、"w"(只写)、"a"(追加)
3. 返回值
  • 成功:返回一个 FILE* 类型的指针(称为 '文件句柄'),后续所有操作都要靠这个指针定位文件;
  • 失败:返回 NULL(比如文件不存在、权限不足),此时需要用 perror 或 strerror 查看错误原因。
4. 关键细节:路径解析逻辑

如果 filename 不带路径(比如 "test.txt"),fopen 会默认在**进程的当前工作目录(CWD)**下找文件。进程的 CWD 从哪里来?—— 来自进程 PCB(进程控制块)中的 cwd 字段(上一篇提到的 /proc/[PID]/cwd 符号链接就是它的映射)。

比如你的程序在 /home/user 目录下运行,fopen("test.txt", "r") 会去找 /home/user/test.txt;如果程序在 /tmp 目录下运行,就会找 /tmp/test.txt。

5. 示例代码:打开文件并判断是否成功
#include <stdio.h>
#include <string.h> // 用于 strerror
#include <errno.h>  // 用于 errno

int main() {
    // 以只读模式打开当前目录下的 test.txt
    FILE *fp = fopen("test.txt", "r");
    
    // 关键:判断打开是否成功(必须做!否则 fp 为 NULL 会导致后续操作崩溃)
    if (fp == NULL) {
        // 方法 1:用 perror 直接打印错误(简单)
        perror("fopen failed");
        // 方法 2:用 strerror 获取错误描述(更灵活)
        // printf("fopen failed: %s\n", strerror(errno));
        return 1; // 打开失败,退出程序
    }
    printf("文件打开成功!\n");
    fclose(fp); // 记得关闭文件(后续讲)
    return 0;
}

如果 test.txt 不存在,运行结果会显示:

fopen failed: No such file or directory 
2. 最后一步:关闭文件 —— fclose

文件操作完成后,必须用 fclose 关闭文件—— 就像 '离开房间要关门',否则会导致资源泄漏(比如文件描述符被占用、缓冲区数据丢失)。

1. 函数语法
#include <stdio.h>
int fclose(FILE *stream);
2. 参数与返回值
  • 参数 stream:fopen 返回的 FILE* 指针(要关闭的文件句柄);
  • 返回值:
    • 成功:返回 0;
    • 失败:返回 EOF(通常是 -1,比如文件已经被关闭),错误原因存放在 errno 中。
3. 为什么必须关闭文件?
  • 释放资源:每个进程能打开的文件数量有限(默认一般是 1024 个),不关闭会导致 '文件描述符耗尽',后续无法打开新文件;
  • 刷新缓冲区:C 库 IO 默认有 '用户态缓冲区'(下一篇详细讲),fclose 会自动刷新缓冲区 —— 如果不关闭,缓冲区中未写入磁盘的数据会丢失。
4. 示例代码:关闭文件并判断
#include <stdio.h>

int main() {
    FILE *fp = fopen("test.txt", "w");
    if (fp == NULL) {
        perror("fopen failed");
        return 1;
    }
    
    // 写入数据(后续讲 fwrite)
    const char *msg = "hello C lib IO!";
    fwrite(msg, strlen(msg), 1, fp);
    
    // 关闭文件并判断是否成功
    if (fclose(fp) != 0) {
        perror("fclose failed");
        return 1;
    }
    printf("文件关闭成功!\n");
    return 0;
}
3. 写入数据 —— fwrite

fwrite 用于将内存中的数据以二进制形式写入文件,支持写入文本、整数、结构体等任意数据(注意:写入的是 '原始二进制',不是 '文本格式')。

1. 函数语法
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
2. 参数解析(重点!容易混淆)

fwrite 的参数设计很巧妙,用 '单个数据块大小 × 数据块个数' 来描述要写入的数据,而不是直接传 '总字节数'—— 这样更灵活(比如写入数组时不用手动算总字节数)。

参数名含义示例
ptr指向 '要写入数据' 的内存起始地址(比如数组名、变量地址)&num(变量地址)、msg(字符串数组名)
size单个数据块的字节数(比如 sizeof(int)、sizeof(char))写入 int 时传 sizeof(int),写入字符时传 1
nmemb要写入的数据块个数写入 5 个 int 时传 5,写入字符串时传 strlen(msg)
stream目标文件的 FILE* 指针fp(之前 fopen 返回的指针)
3. 返回值
  • 成功:返回 '实际写入的数据块个数'(正常情况下等于 nmemb);
  • 失败 / 部分写入:返回值小于 nmemb(比如磁盘满了、文件被意外关闭),此时需要结合 ferror 判断是否为错误。
4. 关键场景:写入文本 vs 写入二进制

很多人会用 fwrite 写入文本,但容易忽略 '二进制' 特性 —— 我们通过两个例子对比:

场景 1:写入字符串(文本)
#include <stdio.h>
#include <string.h>

int main() {
    FILE *fp = fopen("text.txt", "w");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }
    const char *msg = "hello fwrite!";
    // 字符串,末尾有隐藏的 '\0'
    // 写入字符串:单个字符 1 字节,共 strlen(msg) 个字符(不含 '\0',避免乱码)
    size_t write_cnt = fwrite(msg, 1, strlen(msg), fp);
    if (write_cnt != strlen(msg)) {
        printf("写入失败!实际写入%d个字符\n", write_cnt);
    } else {
        printf("写入成功!共写入%d个字符\n", write_cnt);
    }
    fclose(fp);
    return 0;
}

运行后用 cat text.txt 查看,会显示 hello fwrite! —— 因为我们写入的是 '字符的 ASCII 码',文本编辑器能正常解析。

场景 2:写入整数(二进制)
#include <stdio.h>

int main() {
    FILE *fp = fopen("binary.bin", "wb"); // 用 "wb" 模式(二进制写)
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }
    int num = 1234567; // 整数在内存中占 4 字节(32 位系统)
    // 写入整数:单个 int 4 字节,共 1 个数据块
    size_t write_cnt = fwrite(&num, sizeof(int), 1, fp);
    if (write_cnt != 1) {
        printf("整数写入失败!\n");
    } else {
        printf("整数写入成功!\n");
    }
    fclose(fp);
    return 0;
}

运行后用 cat binary.bin 查看,会显示乱码 —— 因为 fwrite 写入的是 1234567 的原始二进制(00010010 11010110 10000111),不是文本格式的 '1234567'。如果要让整数以文本形式写入,需要先用 sprintf 转成字符串,再用 fwrite 写入。

4. 读取数据 —— fread

fread 与 fwrite 对应,用于从文件中读取二进制数据到内存缓冲区,同样支持读取文本、整数、结构体等数据。

1. 函数语法
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
2. 参数解析(与 fwrite 对称)
参数名含义示例
ptr指向 '存储读取数据' 的内存缓冲区(比如数组、变量地址)buf(字符数组名)、&num(int 变量地址)
size单个数据块的字节数读 int 时传 sizeof(int),读字符时传 1
nmemb计划读取的数据块个数计划读 1024 个字符时传 1024
stream源文件的 FILE* 指针fp(fopen 返回的指针)
3. 返回值(重点!需结合场景判断)

fread 的返回值是 '实际读取的数据块个数',有三种常见情况:

  • 等于 nmemb:读取成功,获取到了期望的所有数据;
  • 小于 nmemb 但大于 0:部分读取(比如文件剩余数据不足,或非阻塞 IO 场景);
  • 等于 0:两种可能 ——① 到达文件末尾(EOF);② 读取错误(需用 feof 和 ferror 区分)。
4. 示例:读取文本文件(实现简单 '读文件' 功能)
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024 // 缓冲区大小,每次读 1024 字节

int main() {
    // 1. 打开文件(只读模式)
    FILE *fp = fopen("test.txt", "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }
    
    // 2. 循环读取文件
    char buf[BUF_SIZE] = {0}; // 存储读取数据的缓冲区
    while (1) {
        // 每次读 1 字节,最多读 BUF_SIZE 个字符(即 1024 字节)
        size_t read_cnt = fread(buf, 1, BUF_SIZE - 1, fp); // 留 1 字节存 '\0'
        if (read_cnt > 0) {
            buf[read_cnt] = '\0'; // 给字符串加结束符,避免乱码
            printf("读取到%d字节:%s", read_cnt, buf);
        }
        
        // 3. 判断是否读取结束或出错
        if (feof(fp)) {
            // 到达文件末尾
            printf("\n文件读取完毕!\n");
            break;
        }
        if (ferror(fp)) {
            // 读取错误
            perror("fread failed");
            break;
        }
    }
    
    // 4. 关闭文件
    fclose(fp);
    return 0;
}

运行后会逐段打印 test.txt 的内容 —— 这就是 cat 命令的核心逻辑之一。

5. 判断文件末尾 —— feof

很多人会误用 feof:以为 'feof 返回真就是读取失败',但实际它的作用是判断 '上一次读取操作是否到达文件末尾'(不是 '是否即将到达末尾')。

1. 函数语法
#include <stdio.h>
int feof(FILE *stream);
2. 返回值
  • 非 0 值(真):上一次读取操作已经到达文件末尾(EOF);
  • 0(假):上一次读取操作未到达末尾,或文件未被读取过。
3. 常见误区:用 feof 判断 '是否继续读取'

错误写法(先判断 feof,再读取):

// 错误示例:先判断 feof,再读
while (!feof(fp)) {
    fread(buf, 1, BUF_SIZE, fp); // 可能多读一次空数据
    printf("%s", buf);
}

为什么错?因为 feof 只有在 '读取到 EOF 后' 才会返回真 —— 第一次进入循环时,文件还没读,feof 返回假,执行 fread;如果 fread 刚好读到文件末尾,feof 还是假,会再次进入循环,执行 fread(此时 fread 返回 0,读取空数据),最后 feof 才返回真,跳出循环。

正确写法:先读取,再用 feof 判断是否结束(就像前面 fread 示例那样):

// 正确示例:先读,再判断
while (1) {
    size_t read_cnt = fread(buf, 1, BUF_SIZE, fp);
    if (read_cnt > 0) {
        /* 处理数据 */
    }
    if (feof(fp)) {
        // 上一次 read 到达末尾
        break;
    }
    if (ferror(fp)) {
        // 上一次 read 出错
        perror("read failed");
        break;
    }
}

二、关键知识点:C 库 IO 的 6 种核心打开模式

fopen 的 mode 参数决定了文件的 '操作权限' 和 '行为特性',这是最容易混淆的部分 —— 我们用表格清晰对比 6 种核心模式,再结合场景说明用法。

1. 6 种模式对比表
模式读写权限文件不存在时文件存在时写入行为适用场景
r只读打开失败保留内容不允许写入读取已存在的文本 / 配置文件
r+读写打开失败保留内容从文件开头覆盖写入读写已存在的文件(不创建)
w只写创建文件清空内容(截断)从文件开头写入创建新文件或覆盖旧文件
w+读写创建文件清空内容(截断)从文件开头写入读写新文件或覆盖旧文件
a只写(追加)创建文件保留内容从文件末尾追加写入写日志(不覆盖旧内容)
a+读写(追加)创建文件保留内容写入:末尾追加;读取:从头开始读写日志(既能读历史,又能追加)
2. 关键模式辨析(避坑指南)
  1. w 和 a 的区别:
    • w:无论文件是否存在,都会清空内容(即使文件有 100MB,用 w 打开后也会变成 0KB);
    • a:不会清空文件,新数据永远追加到末尾(比如日志文件必须用 a 模式,否则会覆盖历史日志)。
  2. r+ 和 w+ 的区别:
    • r+:文件必须已存在,否则打开失败(适合修改已有的文件);
    • w+:文件不存在则创建,存在则清空(适合创建新的读写文件)。
  3. 二进制模式(b 后缀):在 Windows 下,文本文件和二进制文件的换行符处理不同(文本用 \r\n,二进制用 \n),所以需要加 b 后缀(比如 rb/wb);但在 Linux 下,文本和二进制文件的换行符处理一致,b 后缀可加可不加 ——为了跨平台兼容,建议写二进制文件时加 b(比如 wb/rb)。

三、C 语言默认打开的 3 个流:stdin、stdout、stderr

你可能没注意过:C 程序启动时,会默认打开 3 个 '特殊文件'—— 它们是标准输入(stdin)、标准输出(stdout)、标准错误输出(stderr),对应的 FILE* 指针由 C 库预先定义,直接就能用。

1. 3 个默认流的作用
流名称对应设备文件描述符(底层)作用常用接口
stdin键盘0接收用户输入(比如 scanf)fscanf(stdin, ...)、fread(..., stdin)
stdout显示器1输出正常信息(比如 printf)printf(...)(等价于 fprintf(stdout, ...))
stderr显示器2输出错误信息(比如 perror)fprintf(stderr, "错误:...")
2. 为什么默认打开这 3 个流?

因为程序的核心是 '数据处理',而数据处理需要 '输入(来源)' 和 '输出(去向)'——stdin 是默认输入源(键盘),stdout/stderr 是默认输出目标(显示器),这样程序启动就能直接交互,不用手动打开。

3. 实战:输出信息到显示器的 3 种方法

我们可以用 printf、fprintf、fwrite 三种方式输出到 stdout(最终都显示在显示器上),代码如下:

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

int main() {
    // 方法 1:printf(默认输出到 stdout)
    printf("hello printf!\n");
    
    // 方法 2:fprintf(显式指定 stdout)
    fprintf(stdout, "hello fprintf!\n");
    
    // 方法 3:fwrite(二进制写入到 stdout)
    const char *msg = "hello fwrite!\n";
    fwrite(msg, strlen(msg), 1, stdout);
    
    return 0;
}

运行结果:

hello printf! hello fprintf! hello fwrite!

三种方法的本质:printf 是 fprintf 的简化版(默认传 stdout),fwrite 是直接写入 stdout 对应的文件 —— 最终都通过 stdout 输出到显示器。

四、实战案例:用 C 库 IO 实现两个常用工具

光学接口不够,我们通过两个实战案例巩固知识点:实现 cat 命令(读取文件并输出)、实现文件拷贝工具(读源文件→写目标文件)。

1. 案例 1:实现简化版 cat 命令

cat 命令的核心逻辑是:打开指定文件→循环读取内容→输出到 stdout→关闭文件。我们还要加上 '命令行参数校验'(用户必须传入文件名)。

完整代码
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    // 1. 校验命令行参数(argc=程序名 + 文件名,共 2 个参数)
    if (argc != 2) {
        // 提示用法:./mycat 文件名
        fprintf(stderr, "用法:%s <文件名>\n", argv[0]);
        return 1;
    }
    
    // 2. 打开文件(只读模式)
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL) {
        perror("fopen failed");
        return 1;
    }
    
    // 3. 循环读取文件,输出到 stdout
    char buf[BUF_SIZE] = {0};
    while (1) {
        size_t read_cnt = fread(buf, 1, BUF_SIZE - 1, fp);
        if (read_cnt > 0) {
            buf[read_cnt] = '\0';
            fwrite(buf, 1, read_cnt, stdout); // 输出到显示器
        }
        
        // 4. 判断结束或错误
        if (feof(fp)) {
            break;
        }
        if (ferror(fp)) {
            perror("fread failed");
            break;
        }
    }
    
    // 5. 关闭文件
    fclose(fp);
    return 0;
}
编译与运行
# 编译代码
gcc mycat.c -o mycat

# 创建测试文件
echo "hello mycat!" > test.txt

# 运行自定义 cat 命令
./mycat test.txt

# 输出结果:hello mycat!
2. 案例 2:实现文件拷贝工具(mycopy)

文件拷贝的逻辑是:打开源文件(读)→ 打开目标文件(写)→ 读源文件→写目标文件→关闭两个文件。

完整代码
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    // 1. 校验参数(argc=程序名 + 源文件 + 目标文件,共 3 个参数)
    if (argc != 3) {
        fprintf(stderr, "用法:%s <源文件> <目标文件>\n", argv[0]);
        return 1;
    }
    const char *src_file = argv[1]; // 源文件路径
    const char *dest_file = argv[2]; // 目标文件路径
    
    // 2. 打开源文件(只读)和目标文件(只写,不存在则创建,存在则覆盖)
    FILE *src_fp = fopen(src_file, "r");
    if (src_fp == NULL) {
        perror("fopen src failed");
        return 1;
    }
    
    FILE *dest_fp = fopen(dest_file, "w");
    if (dest_fp == NULL) {
        perror("fopen dest failed");
        fclose(src_fp); // 别忘了关闭已打开的源文件
        return 1;
    }
    
    // 3. 循环拷贝:读源文件→写目标文件
    char buf[BUF_SIZE] = {0};
    size_t total_copy = 0; // 统计拷贝的总字节数
    while (1) {
        size_t read_cnt = fread(buf, 1, BUF_SIZE, src_fp);
        if (read_cnt > 0) {
            // 写入目标文件
            size_t write_cnt = fwrite(buf, 1, read_cnt, dest_fp);
            if (write_cnt != read_cnt) {
                fprintf(stderr, "写入目标文件失败!\n");
                break;
            }
            total_copy += write_cnt;
        }
        
        // 4. 判断结束或错误
        if (feof(src_fp)) {
            printf("拷贝成功!共拷贝%d字节\n", total_copy);
            break;
        }
        if (ferror(src_fp)) {
            perror("读源文件失败");
            break;
        }
        if (ferror(dest_fp)) {
            perror("写目标文件失败");
            break;
        }
    }
    
    // 5. 关闭文件(先关目标文件,再关源文件)
    fclose(dest_fp);
    fclose(src_fp);
    return 0;
}
编译与运行
# 编译代码
gcc mycopy.c -o mycopy

# 创建 100KB 的测试文件
dd if=/dev/zero of=src.bin bs=1024 count=100

# 拷贝文件
./mycopy src.bin dest.bin

# 验证拷贝结果(比较两个文件是否一致)
diff src.bin dest.bin

# 无输出表示文件一致,拷贝成功

五、C 库 IO 的错误处理技巧

写文件操作代码时,'忽略错误' 是最常见的 bug 来源 —— 比如 fopen 返回 NULL 不处理,程序会崩溃;fwrite 返回值小于 nmemb 不处理,会导致数据丢失。这里教你一套完整的错误处理方法。

1. 核心工具:errno + perror + strerror
  • **errno**:全局变量(定义在 <errno.h> 中),存储最近一次系统调用 / 库函数的错误码(0 表示无错误);
  • **perror(const char *s)**:打印错误信息,格式是 's: 错误描述'(比如 perror("fopen") 会输出 fopen: No such file or directory);
  • **strerror(int errnum)**:将错误码转为字符串描述(比如 strerror(2) 返回 No such file or directory)。
2. 错误处理流程(通用模板)
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main() {
    FILE *fp = fopen("test.txt", "r");
    
    // 1. 检查 fopen 错误
    if (fp == NULL) {
        // 方法 1:perror(简单直接)
        perror("fopen failed");
        // 方法 2:strerror(灵活,可自定义格式)
        // fprintf(stderr, "fopen failed: %s (错误码:%d)\n", strerror(errno), errno);
        return 1;
    }
    
    char buf[1024] = {0};
    
    // 2. 检查 fread 错误
    size_t read_cnt = fread(buf, 1, 1024, fp);
    if (read_cnt == 0) {
        if (feof(fp)) {
            printf("已到达文件末尾\n");
        } else if (ferror(fp)) {
            perror("fread failed");
        }
    }
    
    // 3. 检查 fclose 错误
    if (fclose(fp) != 0) {
        perror("fclose failed");
        return 1;
    }
    return 0;
}

六、常见坑与避坑指南

  1. 忘记关闭文件(资源泄漏):每次 fopen 后必须对应 fclose,尤其是在函数中途返回时(比如 fopen 目标文件失败,要先关闭源文件再返回)。
  2. fwrite 写入字符串时带 \0:字符串末尾的 \0 是 C 语言的 '字符串结束符',不是内容的一部分 —— 用 fwrite 写入时,要传 strlen(msg) 而不是 strlen(msg)+1,否则文件会多一个 \0(文本编辑器打开可能显示乱码)。
  3. 误用 feof 判断读取循环:记住 '先读取,再判断 feof',不要 '先判断 feof,再读取',避免多读一次空数据。
  4. 打开模式选错导致数据丢失:写日志用 a 模式,不要用 w 模式;修改已有文件用 r+ 模式,不要用 w+ 模式(w+ 会清空文件)。

七、总结

这篇我们系统学习了 C 语言标准库 IO 的核心接口:

  • 打开 / 关闭文件:fopen/fclose(记得判断返回值);
  • 读写数据:fread/fwrite(理解 '数据块大小 × 个数' 的参数设计);
  • 判断末尾:feof(先读再判断,避免误用);
  • 打开模式:6 种模式的区别(重点是 w/a、r+/w+ 的差异)。

通过实战案例(实现 cat、文件拷贝),我们把这些接口串起来,理解了 '文件操作的全流程'。

目录

  1. 一、核心接口拆解:从打开到关闭的全流程
  2. 1. 第一步:打开文件 —— fopen
  3. 1. 函数语法
  4. 2. 参数解析
  5. 3. 返回值
  6. 4. 关键细节:路径解析逻辑
  7. 5. 示例代码:打开文件并判断是否成功
  8. 2. 最后一步:关闭文件 —— fclose
  9. 1. 函数语法
  10. 2. 参数与返回值
  11. 3. 为什么必须关闭文件?
  12. 4. 示例代码:关闭文件并判断
  13. 3. 写入数据 —— fwrite
  14. 1. 函数语法
  15. 2. 参数解析(重点!容易混淆)
  16. 3. 返回值
  17. 4. 关键场景:写入文本 vs 写入二进制
  18. 场景 1:写入字符串(文本)
  19. 场景 2:写入整数(二进制)
  20. 4. 读取数据 —— fread
  21. 1. 函数语法
  22. 2. 参数解析(与 fwrite 对称)
  23. 3. 返回值(重点!需结合场景判断)
  24. 4. 示例:读取文本文件(实现简单 “读文件” 功能)
  25. 5. 判断文件末尾 —— feof
  26. 1. 函数语法
  27. 2. 返回值
  28. 3. 常见误区:用 feof 判断 “是否继续读取”
  29. 二、关键知识点:C 库 IO 的 6 种核心打开模式
  30. 1. 6 种模式对比表
  31. 2. 关键模式辨析(避坑指南)
  32. 三、C 语言默认打开的 3 个流:stdin、stdout、stderr
  33. 1. 3 个默认流的作用
  34. 2. 为什么默认打开这 3 个流?
  35. 3. 实战:输出信息到显示器的 3 种方法
  36. 四、实战案例:用 C 库 IO 实现两个常用工具
  37. 1. 案例 1:实现简化版 cat 命令
  38. 完整代码
  39. 编译与运行
  40. 编译代码
  41. 创建测试文件
  42. 运行自定义 cat 命令
  43. 输出结果:hello mycat!
  44. 2. 案例 2:实现文件拷贝工具(mycopy)
  45. 完整代码
  46. 编译与运行
  47. 编译代码
  48. 创建 100KB 的测试文件
  49. 拷贝文件
  50. 验证拷贝结果(比较两个文件是否一致)
  51. 无输出表示文件一致,拷贝成功
  52. 五、C 库 IO 的错误处理技巧
  53. 1. 核心工具:errno + perror + strerror
  54. 2. 错误处理流程(通用模板)
  55. 六、常见坑与避坑指南
  56. 七、总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Java 和 Leaflet 的湖南省道路长度 WebGIS 构建
  • Docker 在 Windows 和 Linux 上的部署配置全流程
  • 自然语言处理在教育领域的应用与实战
  • Python 网络爬虫基础与通用模板实现
  • 从 Web 到 API 驱动:Django REST Framework 重构智能合同审查系统
  • Visual C++ Redistributable 运行时组件问题修复指南
  • LeetCode 720. 字典中最长单词(Python 实现)
  • AI 辅助编写 pytest 单元测试:覆盖率提升实战
  • 多智能体协作驱动的多模态医疗大模型系统:RAG-KAG 双路径知识增强与架构设计
  • 堆排序原理与 C++ 实现
  • Web 聊天室消息加解密方案详解
  • C++ 递归实战:合并两个有序链表与反转链表
  • 老款 Mac 运行本地 AI:OpenClaw 环境一键搭建
  • OpenClaw 记忆系统实战:Token 压缩与双层记忆架构
  • STL 文件预览工具 stl-thumb 安装与使用指南
  • ThreadLocal 的原理、场景和内存泄漏坑
  • 即梦 AI 基础操作指南:绘画与视频生成入门
  • C++ 继承实战:从语法细到员工管理系统
  • Cursor 中配置和使用 MCP 服务详解
  • 二分查找实战:x 的平方根与搜索插入位置解析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online