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

C++与Linux基础:语言特性上的文件操作

Linux 下文件操作涉及磁盘 IO 及一切皆文件概念。介绍 C 语言六种文件打开模式(r/w/a 及其变体),演示 fopen 创建与读写流程,对比 fprintf 与 fwrite 在字符与二进制存储上的区别,并讲解 fread 读取内存块的方法。通过示例代码展示如何安全处理文件指针、缓冲区及换行符,为后续系统级文件调用奠定基础。

开源信徒发布于 2026/2/25更新于 2026/9/475 浏览
C++与Linux基础:语言特性上的文件操作

1. 前置介绍

在上两篇文章中,我们已经写好了一个基本的 Shell,借助这个小实验理解了进程和进程之间的切换,利用子程序来执行外部命令。这里我们要学习的是 Linux 系统的文件篇。在这篇文章,你可以认识到:

  1. Linux 下,一切都是文件(概念)
  2. C 语言中的六种打开模式
  3. C 语言的打开文件的操作
  4. 引入系统接口:系统函数打开文件操作

在 Linux 系统编程中我们已经结束了进程篇,文件篇已经开始启航了。

2. 理解 Linux 下的文件

在我们的日常生活中,我们经常能够看到我们操作 Windows 平台的文件,其实 Linux 里面也是一样的。

2-1 简单的理解(狭义)

文件存储在磁盘中,磁盘是永久存储性容器,它不会因为断电而导致文件消失。因此我们可以引出以下几个点:

  1. 我们对文件的操作就是在磁盘中读取和操作。
  2. 磁盘是外设,对磁盘的输入和输出就是 IO 操作。
  3. 盘上的文件本质是对文件的所有操作,都是对外设的输入和输出简称 IO。

2-2 深入理解

我们在之前也说过,Linux 下一切皆文件,不仅仅是磁盘里面的文件。比如我们的显示屏、键盘或者网卡,他们的本质都是文件。 在之前的文章中,我们讲了一个概念:先描述,再组织,这是很重要的概念,在这里我们也适用:我们也是通过结构体来描述这些文件,最后通过链表组织和运行他们。

当你打开一个空的文件夹的时候,这个文件是否占据内存呢? 答案是显而易见的,他还是占据内存的。尽管在 Windows 平台上显示是 0 个字节,但是其实占据空间的。这里我们指出 文件 = 属性 + 里面的数据。

接下来我们来详细讲解一下 C 语言风格的打开文件吧:

3. C 语言打开文件的模式

先看 C 语言提供了几种打开的方式吧,在学习 C 语言的时候,我们都说有三种大的方向:

  1. r 模式:只读模式:如果文件不存在,就无法读取。
  2. w 模式:写入模式:如果文件不存在,会创建一个文件。注意在写入的时候会清空之前写的内容。
  3. a 模式:追加模式:如果文件不存在,仍然会创建一个文件。与 w 模式不同的是:它会在文件之后追加写入。

这只是三个最基础的,我们还可以在它的后面加上一个 + 号,最后一共是三个大方向,六个模式:

带上 + 号的核心意义是:开启'更新'(Update)模式,允许对同一个文件流既进行读取,又进行写入。

3-1 来尝试 w 模式

我们可以来尝试用程序,来打开或者创建程序来看看吧:

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

int main() {
    FILE* fp = fopen("log.txt", "w");
    if (fp == NULL) {
        perror("open error");
        exit(1);
    }
    char* buff = "hello world";
    fprintf(fp, "%s", buff); // 以指定的格式写入文件中
    return 0;
}

我们先看这个文件夹内是没有 log.txt 的。开始执行之后,我们再次打开这个文件,我们会发现,文件被创建而且,写入成功。

在这里我们是没有找到路径,他是怎么知道的呢?其实当我们运行的时候,进程里面会保存系统环境变量,其中就有一个信息就是 PWD,我们不给路径,他就默认在这个 PWD 里面拼接文件名,进行创建。

3-2 尝试只读模式(r)

在上面的文件夹中,我们已经创建并且写入成功了,这次我们尝试打开这个文件并读取里面的内容:

FILE* fp = fopen("log.txt", "r");
if (fp == NULL) {
    perror("open error");
    exit(1);
}
char buff[15];
fscanf(fp, "%s", buff);
printf("%s", buff);
fclose(fp);
return 0;

我们将文件中的内容以字符串导入 buff 之中,但是这里还有一个问题,我们来看运行结果:我们可以看到,这里我们只打印了一个 hello。

这是因为 fscanf 只能读取一个完整的句子,当他遇到一个空格的时候,他就会结束读取。

这里我们就要换其他的接口来完成这个内容了。我们可以尝试使用 fgets 来完成这个内容的提取,同时,为了读取多个句子,我们使用 while 来完成获取里面的所有的句子。

fgets 一旦遇到 \n 就会停止读取,但是为了防止文件有多个句子,我们使用 while 来循环读取,直到遇到文件结尾:EOF(end of file)就会结束。

可以看到结果,完美的打印了这一句话,并没有出现上面只打印了一个 hello。

4. 文件操作的三巨头:fprintf、fwrite、fread

在上面我们已经详细提到了 fprintf,这个就是像指定文件中输入,比如可以像标准输出(显示屏)中输入字符串。主要是操作字符的,和 fscanf 一样。(上面也提到了他的缺点。) 这里我们着重讲:fwrite、fread:

4-1:fwrite(数据指针,块大小,块数量,fp)

  • 作用:直接把内存块'复印'到文件里。
  • 区别:如果你存数字 100:
  • fprintf 存的是字符 '1', '0', '0' (3 个字节)。
  • fwrite 存的是 int 的二进制原码 (4 个字节),用记事本打开是乱码。

在这里我们也可以尝试来写一下:

FILE* fp = fopen("log.txt", "w");
if (fp == NULL) {
    perror("open error");
    exit(1);
}
char* msg = "hello world\n";
int cnt = 10;
while (cnt--) {
    // 将 msg 的内容传递给 buff,传第一次,n 是为了安全写入,告诉有多少的内存
    char buff[1024];
    snprintf(buff, sizeof(buff), "%s%d\n", msg, cnt);
    fwrite(buff, strlen(buff), 1, fp);
}
fclose(fp);
return 0;

注意这里面 fwrite 的用法:我们 strlen 是计算 \0 之前的内容,我们是不希望 \0 进入我们的文件中的。

这是因为:是给人看的。记事本不需要(也不喜欢)\0,它看到 \0 可能会显示成乱码方块或者这就截断显示了。内存字符串:必须有 \0,否则 CPU 不知道字符串在哪里结束。

来看看以下结果:可以看到这样是没有问题的。接下来,简单来写写 fread。

4-2 fread(数据指针,块大小,块数量,fp)

把磁盘中文件写回内存中,我们来看一个代码:

FILE* fp = fopen("log.txt", "r");
if (fp == NULL) {
    perror("open error");
    exit(1);
}
char buff[1024];
// 这里的 n 指的是本次读取几个字节
int n = fread(buff, 1, sizeof(buff) - 1, fp);
if (n > 0) buff[n] = '\0';
else buff[0] = '\0';
printf("%s", buff);
fclose(fp);

注意这里的 fread 的格式:必须每次读取一个字节,读取 sizeof(buff) - 1 个大小,必须强制留个 \0 一个空间,这样再内存中打印时没有问题的。

5. 引入系统层面的调用

在上文讲了,这些都是语言层面上的调用,不同的语言具有自己的调用方式,JAVA 还是 C++ 都有自己的一套函数来完成这个。 我们这里着重介绍了 C 语言的文件管理。后面,我们回详细讲一下系统层面的调用,还有三个标准输入和输出和错误。

目录

  1. 1. 前置介绍
  2. 2. 理解 Linux 下的文件
  3. 2-1 简单的理解(狭义)
  4. 2-2 深入理解
  5. 3. C 语言打开文件的模式
  6. 3-1 来尝试 w 模式
  7. 3-2 尝试只读模式(r)
  8. 4. 文件操作的三巨头:fprintf、fwrite、fread
  9. 4-1:fwrite(数据指针,块大小,块数量,fp)
  10. 4-2 fread(数据指针,块大小,块数量,fp)
  11. 5. 引入系统层面的调用

更多推荐文章

查看全部
  • Kali Linux 2025.4 在 VMware 中鼠标不显示的解决方法
  • Java 25 虚拟线程核心优化与使用
  • GitHub 教育认证通过后如何领取 Copilot Pro
  • Cogito-v1-preview-llama-3B:128k 长文本中的跨段落逻辑矛盾检测
  • 美团 EvoCUA 刷新开源 SOTA:具备持续进化能力的计算机操作智能体
  • MixAIHub:主流 AI 模型聚合访问平台
  • 删除排序链表中的重复元素 II(链表)
  • Qwen-Image-Lightning 水墨画生成实战指南
  • C++ 手写 Web 服务器:JSON 序列化与 HTTP 协议实战
  • Antigravity 上手指南:打造 VS Code 风格的 AI IDE
  • core-js 包结构与配置策略:解决前端兼容性问题
  • Apache IoTDB 深度解析时序数据聚合的 GROUP BY 与 HAVING 子句
  • gRPC 跨语言通信实战:C++ 服务端对接 C# 客户端
  • Java Swing 文本域 JTextArea 基础交互示例
  • FPGA Mezzanine Card (FMC) 接口标准与引脚定义
  • 具身智能与视觉:机器人如何理解世界
  • LLM 微调实战:使用 Code-Llama 训练自定义代码数据集
  • 开源低代码平台 Microi 吾码功能与安装指南
  • Ubuntu 下 AMD AI MAX 395+ 使用 ROCm 加速部署千问 Qwen 模型
  • AI 提示词助力代码重构与可读性提升

相关免费在线工具

  • 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