一、标准 IO 核心函数(文件操作)

学习 Linux 函数的核心方法:用好man手册,重点看NAME(功能)、SYNOPSIS(头文件 + 函数原型)、RETURN VALUE(返回值)

1. 文件打开:fopen

FILE *fopen(const char *pathname, const char *mode);
  • 功能:打开指定文件,并关联一个流指针,后续通过流指针操作文件;
  • 参数
  • pathname:要打开的文件名(字符串形式,如 "test.txt");
  • mode:打开模式(核心,决定文件的读写权限);
  • 返回值:成功返回流指针(FILE *),失败返回NULL,且系统会设置errno
核心打开模式说明

r:只读,文件必须存在,不存在则报错;r+:读写,文件必须存在,不存在则报错;

w:只写,文件存在则清空,不存在则创建;w+:读写,文件存在则清空,不存在则创建;

a:追加写,文件存在则末尾追加,不存在则创建;a+:追加读 / 写,文件存在则末尾追加,不存在则创建。

2. 错误信息打印:perror

void perror(const char *s);
  • 功能:根据errno自动打印对应的错误原因,配合fopen等函数的失败判断使用;
  • 参数:自定义的错误提示信息(字符串);
  • 打印效果自定义信息: 系统错误原因(无需手动加\n,函数自动换行);
  • 示例perror("fopen fail"),失败时输出fopen fail: No such file or directory

3. 文件关闭:fclose

int fclose(FILE *stream);
  • 功能:关闭流指针,释放文件相关资源,必须执行,否则会造成资源泄漏;
  • 参数stream:要关闭的流指针;
  • 返回值:成功返回 0,失败返回EOF(宏,值为 - 1),且设置errno

4. 字符级读写:fgetc /fputc

读字符:fgetc
int fgetc(FILE *stream);
  • 功能:将一个字符写入指定流中;
  • 参数c为要写入的字符(ASCII 码),stream为目标流;
  • 返回值:成功返回写入的字符,失败返回EOF

适用场景:逐字符处理文件,可处理文本文件和二进制文件(无格式限制),缺点是效率较低。

5. 字符串级读写:fgets /fputs

读字符串:fgets
char *fgets(char *s, int size, FILE *stream);
  • 功能:从流中读取数据,最多读取 size-1 个字符,自动在末尾添加'\0'(字符串结束符);
  • 参数
    • s:存储读取数据的字符数组;
    • size:读取的最大字节数;
    • stream:源文件流;
  • 返回值:成功返回s,失败 / 到达文件末尾返回NULL
  • 读取结束条件(满足其一即停止):
    1. 读到文件末尾(EOF);
    2. 读到换行符\n\n会被保留在字符数组中);
    3. 读满size-1个字符。
  • 从键盘读取字符串时,用fgets(buf, sizeof(buf), stdin)替代gets(buf)gets存在缓冲区溢出风险)。
写字符串:fputs
int fputs(const char *s, FILE *stream);
  • 功能:将字符串写入指定流中;
  • 参数s为要写入的字符串,stream为目标流;
  • 返回值:成功返回非负数,失败返回EOF
  • 注意:写入时不会输出'\0',遇到'\0'则停止写入。

适用场景:处理文本文件,不适合二进制文件(二进制文件中含'\0',会导致 fputs 提前停止)。

6. 块 / 对象级读写:fread /fwrite(二进制读写)

最常用的高效读写方式,按固定大小的元素读写,适合文本文件和二进制文件,尤其适合处理结构体等固定格式的数据。

读数据:fread
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 功能:从流中读取nmemb个元素,每个元素大小为size字节,保存到ptr指向的空间;
  • 参数
    • ptr:存储数据的缓冲区地址(void*,可接收任意类型);
    • size:单个元素的字节大小;
    • nmemb:要读取的元素个数;
    • stream:源文件流;
  • 返回值:成功返回实际读取的元素个数,失败 / 到达文件末尾返回 0
写数据:fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 功能:将ptr指向的空间中,nmemb个大小为size的元素写入指定流;
  • 参数:同 fread,ptr为待写入数据的缓冲区地址;
  • 返回值:成功返回实际写入的元素个数,失败返回 0。

7. 格式化输出:fprintf /sprintf

文件格式化输出:fprintf
int fprintf(FILE *stream, const char *format, ...);
  • 功能:将格式化的数据写入指定流(文件 / 标准流),是printf的文件版;
  • 示例fprintf(fp, "num = %d, time = %s\n", 1, "2025-01-01");fprintf(stdout, "a = %d\n", a);(等价于printf)。
字符串格式化输出:sprintf
int sprintf(char *str, const char *format, ...);
  • 功能:将格式化的数据写入字符数组,生成指定格式的字符串;
  • 示例sprintf(buf, "name: %s, age: %d", "zhangsan", 18);,buf 中会存储"name: zhangsan, age: 18"

二、文件定位操作:fseek /ftell/rewind

Linux 内核会为每个打开的文件维护文件位置偏移量,读 / 写操作会自动移动该偏移量,默认从文件开头开始。文件定位操作可手动修改偏移量,实现随机读写。

1. 定位偏移量:fseek

int fseek(FILE *stream, long offset, int whence);
  • 功能:将文件偏移量定位到从 whence 开始,偏移 offset 字节的位置;
  • 参数
    • stream:目标文件流;
    • offset:偏移量(可正可负,正为向后偏移,负为向前偏移);
    • whence:参考点(宏定义,核心):
      • SEEK_SET:文件开头(offset 只能为正);
      • SEEK_CUR:当前偏移量位置(offset 可正可负,空文件不能为负);
      • SEEK_END:文件末尾(offset 可正可负);
  • 返回值:成功返回 0,失败返回 - 1;
    fseek(fp, 0, SEEK_SET); // 定位到文件开头
    fseek(fp, 0, SEEK_END); // 定位到文件末尾

    特殊用法:创建空洞文件(文件中填充'\0',可提前抢占磁盘空间,如百度云下载的.downloading文件),步骤:fseek定位到指定位置 → 执行一次写操作

2. 获取偏移量:ftell

long ftell(FILE *stream);
  • 功能:获取当前文件的位置偏移量;
  • 返回值:成功返回偏移量(字节数),失败返回 - 1;
  • 常用场景:计算文件大小
    fseek(fp, 0, SEEK_END); // 定位到文件末尾
    long file_size = ftell(fp); // file_size即为文件总字节数

    3. 重置到文件开头:rewind

    void rewind(FILE *stream);
  • 功能:将文件偏移量重置到文件开头,无返回值;
  • 等价于fseek(fp, 0, SEEK_SET);,语法更简洁。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐