Linux软件编程学习笔记(二)Linux文件IO编程入门:从fopen到fgetc

一、文件的基本概念

在Linux中,文件是存放在磁盘(或其他存储介质)上的一段数据的集合。从操作系统的角度看,一切皆文件,包括普通文件、目录、设备、管道等。我们这里讨论的是普通文件,即存储在文件系统中的数据流。


二、文件操作的三个核心步骤

无论采用何种编程语言,文件操作通常都遵循"三步走"原则:

  1. 打开文件 -- 建立程序与文件之间的连接,获得一个文件流指针。
  2. 读写文件 -- 根据需求读取或写入数据。
  3. 关闭文件 -- 释放资源,确保数据完整写入磁盘。

三、文件类型:ASCII码文件与二进制文件

  • ASCII码文件(文本文件):文件中的每个字符都是可显示的ASCII字符,例如源代码、配置文件、日志等。这类文件可以用文本编辑器直接查看。
  • 二进制文件 :文件中包含不可显示的字符(如0x000xFF等),例如图片、音视频、可执行程序、压缩包等。

本质上,所有文件都是二进制存储的,ASCII码文件只是二进制文件的一种特殊形式,但编程时我们根据内容格式选择不同的读写方式。


四、常用文件IO函数详解

标准C库(stdio.h)提供了一套跨平台的IO接口,在Linux下同样适用。以下逐个介绍最常用的函数。

4.1 fopen -- 打开文件

c 复制代码
FILE *fopen(const char *pathname, const char *mode);
  • 功能 :打开pathname指定的文件,并建立一个与程序关联的(stream)。
  • 参数
    • pathname:文件路径(绝对或相对)。
    • mode:打开方式,常用模式如下:
模式 含义
"r" 只读,文件必须存在,否则返回NULL。
"r+" 读写,文件必须存在。
"w" 只写,文件不存在则创建,存在则清空(长度截为0)。
"w+" 读写,文件不存在则创建,存在则清空。
"a" 追加只写,文件不存在则创建,写入数据追加到文件末尾。
"a+" 追加读写,文件不存在则创建,读可从任意位置,写只能追加到末尾。
  • 返回值 :成功返回FILE*指针,失败返回NULL,并设置errno。

注意 :程序启动时,系统会自动打开三个标准流,无需手动fopen

  • stdin -- 标准输入(键盘)
  • stdout -- 标准输出(终端)
  • stderr -- 标准错误(终端)

4.2 fclose -- 关闭文件

c 复制代码
int fclose(FILE *stream);
  • 功能 :关闭stream指向的流,刷新缓冲区,释放相关资源。
  • 返回值 :成功返回0,失败返回EOF(-1)。

重要 :文件操作完毕后务必调用fclose,否则可能导致数据丢失或资源泄漏。


五、标准IO的缓存机制

标准IO库为了提高效率,会为每个流分配缓冲区。根据刷新条件的不同,缓存分为三类:

缓存类型 大小 刷新条件
全缓存 通常4KB ①缓冲区满;②调用fflush;③程序正常结束或fclose
行缓存 通常1KB ①缓冲区满;②遇到换行符\n;③调用fflush;④程序结束或fclose
不缓存 0(立即刷新) 每次输出都立即刷新(如stderr),用于实时错误信息。
  • 磁盘文件 建立的流默认为全缓存
  • 终端stdout)建立的流默认为行缓存
  • stderr默认为不缓存,保证错误信息及时显示。

我们可以使用fflush(FILE *stream)手动刷新缓冲区,强制将数据写入内核。


六、字符级别的读写:fputcfgetc

6.1 fputc -- 写入一个字符

c 复制代码
int fputc(int c, FILE *stream);
  • 功能 :将字符c写入stream指定的流中。
  • 参数c为要写入的字符(转换为int),stream为目标流。
  • 返回值 :成功返回写入字符的ASCII码值,失败返回EOF

6.2 fgetc -- 读取一个字符

c 复制代码
int fgetc(FILE *stream);
  • 功能 :从stream中读取一个字符。
  • 返回值 :成功返回读取字符的ASCII码值,失败或读到文件末尾返回EOF

示例:统计文件行数

下面是一个完整的程序,用于统计指定文件的行数(换行符\n的数量):

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    int lines = 0;
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '\n') {
            lines++;
        }
    }

    fclose(fp);
    printf("File '%s' has %d lines.\n", argv[1], lines);
    return 0;
}

编译运行:

bash 复制代码
gcc -o line_count line_count.c
./line_count /etc/passwd

七、更多读写函数(简要介绍)

除了字符级别的fputc/fgetc,标准库还提供了行、格式化和二进制级别的读写函数,在实际开发中更为常用:

  • 行读写fputs / fgets -- 读写一行字符串(处理换行符)。
  • 格式化读写fprintf / fscanf -- 按指定格式读写数据,类似printf/scanf但作用于文件。
  • 二进制读写fwrite / fread -- 直接读写内存块,适用于结构体、数组等二进制数据。

八、总结

函数 作用 典型应用场景
fopen 打开文件 建立文件流
fclose 关闭文件 释放资源,保证数据落盘
fputc 写一个字符 逐字符输出,如生成文本
fgetc 读一个字符 逐字符解析,如词法分析
fputs 写字符串 按行写入配置或日志
fgets 读字符串 按行读取配置文件
fprintf 格式化写入 输出带格式的数据
fscanf 格式化读取 解析结构化文本
fwrite 二进制写入 保存结构体、数组到文件
fread 二进制读取 从文件恢复结构体、数组

掌握这些函数,就能应对绝大多数文件操作需求。记住三个要点:打开 → 读写 → 关闭,并留意缓冲区刷新,避免数据丢失。

相关推荐
sunoo-2291 小时前
C 语言文件 IO 全攻略:从基础函数到实战踩坑(BMP 读取 + 词典查询)
linux·c语言·前端·笔记·vscode·学习
雪的季节1 小时前
C++ 高级(泛型编程与模板)(有空再研究吧)
c++
三十岁老牛再出发1 小时前
8月21日总结
c++·python
草莓熊Lotso1 小时前
【Linux网络加餐】手动部署:SSH 与 Web 服务实战 + 底层原理全解析
linux·运维·网络·人工智能·python·langchain·ssh
CHHH_HHH1 小时前
【Linux系统篇】深入解析Linux文件系统:从磁盘寻址到软硬链接
linux·服务器·开发语言·后端·ubuntu
蒸蒸yyyyzwd1 小时前
cpp选手秋招学习笔记 day12
笔记·学习·oracle
Wang's Blog2 小时前
PostgreSQL笔记38:慢查询定位与优化的系统方法论
数据库·笔记·postgresql
GeekPlusA2 小时前
ai-opendesign学习
学习
XiaQ09192 小时前
Linux 常用命令学习笔记(用户管理篇):用户、组与权限的钥匙
linux·开发语言·笔记·学习