Linux中基础IO和文件认识

发布时间:2026/10/19 17:09:37

Linux中基础IO和文件认识 文件1文件在磁盘里2磁盘是永久性存储的介质因此文件在磁盘上存储是永久性的3磁盘是一个外设即是输出设备也是输⼊设备4磁盘上的⽂件本质是对⽂件的所有操作都是对外设的输⼊和输出简称IO0文件的认识1对于0KB的文件来说也是占用一定的磁盘空间2文件文件属性文件内容的集合3所有的⽂件操作本质是⽂件内容操作和⽂件属性操作系统角度认识1对文件的操作本质是进程对文件的操作2磁盘的管理者是操作系统3⽂件的读写本质不是通过C语⾔/C的库函数来操作的这些库函数只是为⽤⼾提供⽅便⽽ 是通过⽂件相关的系统调⽤接⼝来实现的fopen和open带f开头C 标准库stdio.h的文件流函数高层 IO不带f操作系统系统调用POSIX如 Linux底层文件描述符 IO特征带 ffopen,fread,fwrite,fclose,fseek不带 fopen,read,write,close,lseek接口来源C 标准库函数跨平台OS 系统调用POSIX 标准Linux/UnixWindows 也有 API 但接口不一样不跨平台操作对象FILE* 文件指针流int 文件描述符 fd小整数缓冲区✅自带用户态缓冲库缓冲❌无库层缓冲直接调用内核只有内核缓冲文本 / 二进制区分文本模式r和二进制rb没有文本模式全部原始二进制字节换行处理Windows 下自动\n - \r\n转换原样读写字节不做换行转换错误获取ferror()、feof()errno全局变量可移植性所有 C 编译器都能用Windows/Linux/macOSUnix 系Windows 不支持这套要用 Win32API典型函数fopen,fclose,fread,fwrite,fgets,fputs,fprintf,fscanf,fseek,ftell,rewindopen,close,read,write,lseek核心概念1、FILE* 流高层fopen返回FILE *fp这个结构体里面封装了文件描述符 fd再加一块内存缓冲区。 当你调用fread/fwrite数据先读写到库的内存缓冲区不是立刻落到磁盘。刷新缓冲区fflush(fp)强制把缓冲区数据交给操作系统。好处减少系统调用次数读写小数据性能更高。2、文件描述符 fd底层系统调用open()返回 int 整数 fd直接跟操作系统内核打交道没有 C 库的缓冲。 调用read/write就直接发起系统调用每一次都进入内核。频繁小 read/write 性能差因为系统调用有开销。3、二者可以互相转换fileno(FILE* fp)从FILE*拿到底层 fdfdopen(int fd, const char *mode)用已有的 fd 包装成 FILE * 流文本模式 vs 二进制模式FILE *fp fopen(a.txt, r); // 文本模式 FILE *fp fopen(a.txt, rb); // 二进制模式Linux 下文本 / 二进制模式没有区别不会转换换行。open/read 这套底层接口永远等价二进制模式没有文本模式。使用场景普通 C 程序追求可移植、简单文件读写→ 用fopen/fread/fwrite带 f自带缓冲简单。Linux 系统编程管道、socket、设备文件、高级标志非阻塞 O_NONBLOCK锁等→ 用open/read/write系统调用。fopen无法直接设置非阻塞这类内核属性。一句话总结带 f 是 C 标准库封装有缓冲、区分文本二进制、跨平台操作 FILE*不带 f 是操作系统原生系统调用操作文件描述符 fd无库缓冲Unix/Linux 专用。fprintf / snprintf它们都属于stdio.h 标准库函数带 f 家族本质是格式化输出函数核心能力把数字、变量按格式转成字符串。fprintfint fprintf(FILE *stream, const char *format, ...);输出目标FILE*文件流可以是文件、stdout、stderr作用格式化直接写入文件流缓冲区。重点fprintf是基于FILE*流走 C 库缓冲区不是直接写磁盘。数据先到用户缓冲区fflush/fclose 才真正交给内核。printf等价于fprintf(stdout, ...)stdout 就是默认的屏幕 FILE * 流。snprintfint snprintf(char *buf, size_t size, const char *format, ...);输出目标内存缓冲区char 数组内存字符串不碰文件作用格式化把结果写到内存字符数组里。不会直接写入文件。char buf[64]; int a 200; snprintf(buf, sizeof(buf), num%d, a); //此时buf里面存放 num200 字符串和 fopen /open/read/write 的关系关系图fprintf格式化 → 写到FILE*流 → C 库缓冲区 →fflush交给内核 write 系统调用。变量 → fprintf → FILE*缓冲区 → fflush → write()系统调用 → 内核snprintf格式化 →写到内存 char []。之后你可以选择用fputs/fwrite把 buf 写到 FILE * 文件或者拿到 fd调用系统调用write(fd, buf, strlen(buf))写入文件。变量 → snprintf → 内存buf ↓ 方案1fputs(buf, fp) //走FILE*库缓冲 方案2write(fd, buf, strlen(buf)) //直接底层系统调用函数输出目的地是否操作文件底层依赖printfstdout屏幕 FILE*是FILE * 流fprintf任意 FILE*文件 /stdout/stderr是FILE * 流、库缓冲sprintf/snprintf内存 char [] 数组❌不碰文件内存操作纯内存无 IOFILE *fp fopen(test.txt,w); int val 666; fprintf(fp, value:%d\n, val); fclose(fp); FILE *fp fopen(test.txt,w); int val 666; char buf[32]; snprintf(buf,sizeof(buf),value:%d\n,val); fputs(buf, fp); fclose(fp); int fd open(test.txt, O_WRONLY|O_CREAT, 0644); int val 666; char buf[32]; snprintf(buf,sizeof(buf),value:%d\n,val); write(fd, buf, strlen(buf)); //直接系统调用write close(fd);总结fprintf格式化后直接输出到 FILE * 文件流做格式化 IOsnprintf格式化输出到内存字符串只做字符串拼装完全不做 IO可以搭配 fwrite/fputs也可以搭配底层 write 系统调用。内核没有格式化能力格式化逻辑全部在 C 标准库。格式化输出简单说把程序里面各种类型的数据整数、小数、字符转换成人类看得懂的字符串按你指定的样子拼接好再输出出去就叫格式化输出。printf(xxx %d, a)格式化后输出到屏幕 (stdout 流)fprintf(fp, xxx %d, a)格式化后输出到FILE* 文件流文件snprintf(buf, size, xxx %d, a)格式化后输出到内存字符数组 buf不输出到屏幕、不写文件。只是在内存拼好字符串后面你想写到哪里再自己写。dprintf(fd, xxx %d, a)Linux POSIX 扩展 格式化后直接输出到底层文件描述符 fd。等价于先用 snprintf 拼字符串再调用 write。再回到你前面的 fopen /open带 f 的库函数fprintf自带格式化 FILE 流缓冲 IOopen/read/write 系统调用只有原始字节 IO没有格式化。想要输出数字必须先用 snprintf 做格式化把数字变成字符串再 write。一句话总结格式化输出 根据模板把内存里的数字、小数等各种变量转换成可读的字符串拼接成一整段文本。格式化是 C 库做的工作操作系统内核完全不懂%d。OPEN的使用三个参数第一个创建文件的文件名第二个创建文件的属性第三个文件的权限设置第二个属性基础必选只能选一个flags含义O_RDONLY只读打开只能读不能写O_WRONLY只写打开只能写不能读O_RDWR读写打开可读可写常用附加标志用|和上面组合标志作用O_CREAT文件不存在就创建用这个标志时 open 必须传第三个参数 modeO_EXCL和O_CREAT一起文件已存在则 open 报错保证新建文件O_TRUNC如果文件存在打开时直接清空文件内容截断为 0 字节O_APPEND追加写每次 write 都写到文件末尾不会覆盖原有内容打印fd: 3动作流向作用读文件 (read/fgets)磁盘 ➜ 程序内存获取文件内容不显示写 stdout (printf/fputs/write (1,..))程序内存 ➜ 屏幕把内存内容打印出来读文件把磁盘上文件里的数据读取到程序内存变量 / 数组里面。读文件不等于直接打印到屏幕 (stdout)。读磁盘 →程序内存读到数组、buf 缓冲区输出到屏幕内存 → stdoutprintf/fputs做这件事流程读文件把内容拿到内存你自己再写代码把内存里的内容打印到屏幕才会看到输出。使用read/fputs/printf等一句话总结O_RDONLYopen 的参数控制打开之后这个文件描述符能不能写只做权限设置不读取数据。read()系统调用真正从磁盘读字节到内存read 必须依靠 open 返回的 fd。O_RDONLY 是开门权限read 是伸手拿东西。开门≠拿东西。配套记忆open开门获取文件描述符设置权限 (O_RDONLY/O_WRONLY/O_RDWR)read拿数据进来磁盘→内存write把数据送出去内存→磁盘close关门为什么打印3因为系统自动打开了stdin 标准输入 键盘 fd: 0stdout 标准输出 显示器 fd: 1stderr 标准错误 显示器 fd: 2fd名字含义默认目标0stdin标准输入键盘1stdout标准输出屏幕2stderr标准错误输出屏幕对Linux一切接文件重定向重定向本质改变文件描述符指向把本来输出到 A 的内容改输出到文件 / 别的地方。输出重定向、覆盖重定向等价O_WRONLY | O_CREAT | O_TRUNCls out.txt # ls本来打印到屏幕(fd1)现在写到 out.txt文件原有内容全部清空追加重定向等价O_WRONLY | O_CREAT | O_APPENDecho hello log.txt # 写到文件末尾不删除旧内容2代表 stderr错误信息#错误信息写入err.txt正常输出依旧屏幕 cat nofile.txt 2 err.txtdup和dup2函数头文件#include unistd.hint dup(int oldfd); int dup2(int oldfd, int newfd);1️⃣dup(int oldfd)函数行为传入一个已经打开的文件描述符oldfd内核会找当前进程里最小的、没有被占用的文件描述符编号让这个新 fd 和oldfd指向同一个struct file返回这个新的文件描述符。示例 进程默认 fd0 (标准输入)、1 (标准输出)、2 (标准错误)都被占用。int fd open(a.txt, O_WRONLY|O_CREAT,0666); // fd3 int new_fd dup(fd);现在最小空闲 fd 是 4dup(3)返回4。fd3 和 fd4两个编号指向同一个打开的文件对象。⚠️注意文件引用计数 1关闭其中一个 fd另一个还可以继续读写文件只有全部 close内核才真正释放文件对象。dup 特点只能由内核帮你选新的 fd 编号你不能指定新 fd 的值。返回值成功返回新 fd失败返回‑1。2️⃣dup2(int oldfd, int newfd)重定向最常用dup2(oldfd, newfd)把 oldfd 复制到 newfd你自己指定 newfd 是几号。执行逻辑分两步如果newfd原本是一个已经打开的有效文件描述符dup2会自动先 close (newfd)把它关掉。然后让newfd这个编号和oldfd指向同一个struct file。返回值成功返回newfd失败返回‑1。int fd open(log1.txt, O_WRONLY|O_CREAT|O_TRUNC,0666); dup2(fd, 1); // oldfdfd(3), newfd1fd1 原本指向显示器stdoutdup2 自动 close (1)关闭显示器连接。让 fd1 现在指向 log1.txt 的文件对象。printf一直往 fd1 写输出就写入文件不再打印屏幕。dup2 重点细节如果oldfd newfd不会做任何操作直接返回 newfd不会 close。newfd可以是任意数字比如dup2(fd,1)、dup2(fd,2)重定向 stderr。函数参数新 fd 编号谁决定dup(oldfd)只传旧 fd内核自动选最小空闲 fddup2(oldfd, newfd)旧 fd 指定新 fd 编号程序员手动指定 newfd小坑dup、dup2 只是复制描述符不复制缓冲区共用同一个文件偏移量。一个 fd 写文件移动偏移另一个 fd 读写也会看到偏移变化。出错记得判断返回值open 失败得到‑1再传给 dup2 会直接出错。头文件必须unistd.h否则编译警告。shell 重定向./a.out log.txtshell 底层就是 fork 子进程在子进程内部调用dup2()把 fd1 指向文件然后 exec 执行程序程序 printf 就输出到文件。和你代码写dup2(fd,1)做的是一模一样。
延伸阅读

更多相关文章

2026/10/19 17:08:21

2023携程春招技术岗笔试复盘:流程、题型与编程题解析

如果正在准备携程或者其他互联赛道大厂的春招技术岗笔试,这篇关于2023年携程春招技术通用岗第一批笔试的复盘应该能帮到你。我是在去年春季批次参加的这场笔试,当时提前做了不少功课,但真正坐到电脑前才发现,很多细节和策略跟网上…

2026/10/15 5:12:51

如何有效评估dbt分析代理报告:避免误报与盲点的实用指南

在实际的数据工程和数据分析项目中,我们越来越依赖自动化工具来理解、监控和优化数据流水线。dbt(Data Build Tool)作为现代数据栈的核心,其仓库(repo)中包含了定义数据转换逻辑的模型、测试和文档。与此同…

2026/10/19 17:05:36

开源 CLI 代码审查工具:基于 Git 与本地 LLM 的轻量级自检方案

1. 项目概述:一个真正能落地的开源代码审查 CLI 工具“open-code-review”这个名字乍看平平无奇,但拆开来看——open不是指“开源”,而是指“开放上下文”;code-review也不是走形式的 PR 点赞,而是让大模型真正理解你改…

2026/10/19 17:05:36

AI论文工具实战指南:从选题到查重的职称论文写作工作流

1. 职称论文的痛,到底痛在哪每年到了评职称的季节,总有一批人对着空白的Word文档发呆。工作十几年的老工程师、临床经验丰富的医生、带过无数毕业班的老师,业务能力没得说,但一提到写论文就头疼。这不是个别现象,而是职…

2026/10/19 17:05:36

深度学习调参核心:损失函数与优化器选择及训练曲线诊断

深度学习模型的训练效果,七成取决于损失函数和优化器的选择,这个比例一点也不夸张。我见过太多朋友上来就套一个Adam、配一个交叉熵,结果模型不收敛还以为是网络结构写得不对,折腾几天最后发现就是优化器相关的学习率没配好。也有…

2026/10/19 17:05:36

ZXing.Net 0.16.8.0 实战:Unity 与 .NET 条码识别解码优化指南

简介:ZXing.Net.0.16.8.0 是面向 C# 与 Unity 开发者的开源条码处理库,基于 Zebra Crossing 项目,可在 .NET 框架与 Unity 引擎中实现 QR 码、Aztec、Code 128、EAN 等多种条码的读取与生成。开发者只需调用少量 API 即可为桌面应用、移动端或…

2026/10/19 17:00:33

老毛桃v7.0 UEFI启动盘制作全指南:解决双模式识别失败

简介:老毛桃U盘启动盘制作工具(UEFI版 装机版)v7.0是一款面向电脑初学者与系统维护人员的轻量级系统辅助工具,专为快速制作兼容UEFI与传统BIOS的U盘启动盘、安装原版Windows系统及执行PE环境下的系统维护任务而设计。资源包共2个文…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/19 0:04:56

悟空开源无代码平台实战:从实体建模到应用设计避坑指南

简介:基于悟空开源无代码平台的多种应用设计源码,面向希望在不编写代码的情况下快速搭建CRM、HRM、财务系统、ERP、SRM等业务应用的企业与技术人员,通过拖放式界面和内置模板即可完成应用定制与部署。压缩包共697个文件,约10.74MB…

2026/10/19 0:04:56

基于.NET9的多租户权限系统:数据权限与动态API落地实践

简介:这份资源是一套面向 .NET 与 Vue 全栈开发者的中台权限管理系统,后端基于 .Net9,前端采用 Vue3 Element Plus,并配套 uniapp uviewui 移动端方案,实现前后端分离。系统覆盖多租户隔离、数据权限、动态 Api、任务…

2026/10/19 0:04:56

场地预约小程序毕设实战:SSM+微信小程序+MySQL数据库设计到避坑

简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序SSMMySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑