[操作系统] 基础 IO:理解“文件”与 C 接口

在 Linux 操作系统中,“一切皆文件”这一哲学思想贯穿始终。从基础 IO 学习角度来看,理解“文件”不仅仅意味着了解磁盘上存储的数据,还包括对内核如何管理各种资源的认识。本文将从狭义与广义两个层面对“文件”进行解读,归纳文件操作的分类,并从系统角度解析文件的底层实现;接着回顾 C 语言文件接口部分,通过 hello.c 案例展示文件的打开、写入与读取,同时探讨如何将信息输出到显示器、标准流的使用以及各种文件打开方式。


理解“文件”

1-1. 狭义理解

在狭义上,“文件”通常指存储在磁盘中的普通文件。它是由字节(或字符)序列构成的数据集合,在磁盘上以一定的结构保存(如 FAT、ext4 等文件系统)。使用狭义概念时,我们关注的是文件的内容、大小、权限等属性。例如,一个存放文本数据的文件或一个二进制文件,都可以被看作传统意义上的“文件”。文件对外设的输入输出简称IO。

示例代码(仅演示概念,不涉及实际操作):

// 假设 f1.txt 是一个普通文本文件
FILE *fp = fopen("f1.txt", "r");  // 以只读方式打开文件
if (fp == NULL) {perror("打开文件失败");exit(EXIT_FAILURE);
}
// 读取或处理文件...
fclose(fp);
1-2. 广义理解

广义上,Linux 中的“文件”概念远不止传统的磁盘文件。Linux 哲学中**“一切皆文件”**意味着:

  • 设备文件:包括字符设备、块设备,代表硬件(如键盘、显示器、硬盘);
  • 管道和套接字:用于进程间通信;
  • 目录:虽然目录本质上是特殊类型的文件,但它们存储的是文件名和相关元数据;
  • 虚拟文件:例如 /proc 下的各种伪文件,用于显示内核和进程状态。

这种广义的理解使得操作系统将各种资源统一为文件接口,程序员在操作时无需关心底层硬件的细节,只需通过统一的读写操作即可。

1-3. 文件操作的归类认知

文件是文件属性(元数据)文件内容的集合,文件 = 属性 + 内容。

所以所有的文件操作都是对文件内容或者对文件属性操作。

文件操作大体可以分为以下几类:

  • 顺序读写:文件数据按顺序读取和写入。
  • 随机访问:通过定位(如 lseek)在文件中跳转到任意位置进行读写。
  • 标准流操作:通过 C 标准库的 fopen、fread、fwrite、fseek、fclose 等接口操作文件,这是一种缓冲 IO 方式,适用于大多数应用程序。
  • 系统调用接口:使用 open、read、write、lseek、close 等系统调用,直接与内核交互,具有更低的开销和更高的灵活性,但使用较为复杂。

通过这样的分类,我们可以根据实际需求选择合适的接口。

1-4. 系统角度
  1. 对文件的操作本质上是进程对文件的操作。
  2. 磁盘管理者是操作系统,操作系统对打开的文件管理的方式是:先描述,后组织
  3. 文件读写的本质不是通过各种语言的库函数来操作完成的,上层语言知识为了给用户提供方便,而是通过文件相关的系统调用来实现的。

回顾 C 文件接口

2-1. hello.c 打开文件

在 C 语言中,使用 fopen() 打开文件。函数原型如下:

FILE *fopen(const char *filename, const char *mode);

其中,filename 表示文件名(可包含路径),mode 指定打开模式(如 “r”、“w”、“a” 等)。

示例代码:

// hello.c —— 打开文件示例
#include <stdio.h>
#include <stdlib.h>int main(void) {FILE *fp = fopen("hello.txt", "w+"); // 以读写方式打开,如果文件不存在则创建,存在则清空if (fp == NULL) {perror("打开文件失败");exit(EXIT_FAILURE);}printf("文件打开成功,文件指针:%p\n", fp);fclose(fp);return 0;
}

2-2. hello.c 写文件

写文件操作可以使用 fwrite()fputs()fprintf()fputc() 等接口。这里以 fputs() 为例:

fputs("Hello, Linux IO!\n", fp);

或者使用 fprintf() 进行格式化输出:

fprintf(fp, "数字:%d,字符串:%s\n", 123, "abc");

示例代码:

// hello.c —— 写文件示例
#include <stdio.h>
#include <stdlib.h>int main(void) {FILE *fp = fopen("hello.txt", "w+");if (fp == NULL) {perror("打开文件失败");exit(EXIT_FAILURE);}// 使用 fprintf 写入数据fprintf(fp, "Hello, Linux IO!\n");// 使用 fputs 写入字符串fputs("这是通过 fputs 写入的一行文字。\n", fp);fclose(fp);return 0;
}

新文件的创建路径

<font style="color:rgb(31,35,41);">ls /proc/[进程id] -l</font>可以查看当前运行进程的信息。

[@VM-8-12-centos io]$ ps ajx | grep myProc
506729 533463 533463 506729 pts/249 533463 R+ 1002 7:45 ./myProc
536281 536542 536541 536281 pts/250 536541 R+ 1002 0:00 grep --
color=auto myProc
[@VM-8-12-centos io]$ ls /proc/533463 -l
total 0
......
-r--r--r-- 1  0 Aug 26 17:01 cpuset
lrwxrwxrwx 1  0 Aug 26 16:53 cwd -> /home/ddd/io
-r-------- 1  0 Aug 26 17:01 environ
lrwxrwxrwx 1  0 Aug 26 16:53 exe -> /home/ddd/io/myProc
dr-x------ 2  0 Aug 26 16:54 fd

其中:

cwd:指向当前进程运⾏⽬录的⼀个符号链接,当前进程中创建文件的默认相对路径。

exe:指向启动当前进程的可执⾏⽂件(完整路径)的符号链接。

每个进程在运行时都有一个当前工作目录(CWD),这是进程在文件系统中的“当前位置”。当进程打开一个文件时,如果文件路径是相对路径(即不以 / 开头),操作系统会默认将这个路径解析为相对于进程的当前工作目录。

2-3. hello.c 读文件

读文件操作常用的接口包括 fread()fgets()fgetc()。例如,使用 fgets() 逐行读取文件:

char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {printf("%s", buffer);
}

示例代码:

// hello.c —— 读文件示例
#include <stdio.h>
#include <stdlib.h>int main(void) {FILE *fp = fopen("hello.txt", "r");if (fp == NULL) {perror("打开文件失败");exit(EXIT_FAILURE);}char buffer[256];while (fgets(buffer, sizeof(buffer), fp) != NULL) {printf("%s", buffer);}fclose(fp);return 0;
}

稍加改动即可模拟cat命令。

#include <stdio.h>
#include <string.h>int main(int argc, char* argv[]) {// 检查命令行参数数量是否正确if (argc != 2) {printf("argv error!\n");return 1;}// 打开文件FILE *fp = fopen(argv[1], "r");if (!fp) {printf("fopen error!\n");return 2;}// 定义缓冲区char buf[1024];// 循环读取文件内容while (1) {int s = fread(buf, 1, sizeof(buf), fp);if (s > 0) {// 确保字符串以空字符结尾buf[s] = '\0';printf("%s", buf);}if (feof(fp)) {break;}}// 关闭文件fclose(fp);return 0;
}

2-4. 输出信息到显示器,你有哪些方法

在 C 语言中,将信息输出到显示器有多种方式:

  • printf():最常用,直接向标准输出(stdout)输出格式化字符串。
  • puts():输出字符串,并自动追加换行符。
  • fprintf(stdout, …):与 printf() 类似,但明确指定输出到 stdout。
  • fputs():输出字符串,但不自动追加换行符。
  • putchar()/fputc():逐字符输出。

每种方法各有优势,选择时可根据需求决定是否需要格式化、是否自动换行等。

2-5. stdin & stdout & stderr

在 C 语言中,标准流定义在 <stdio.h> 中:

  • stdin:标准输入流(默认绑定键盘)。
  • stdout:标准输出流(默认绑定显示器)。
  • stderr:标准错误流(默认绑定显示器,用于输出错误信息)。

这些流也是文件,在程序启动时添加打开这些流的代码,自动打开,所以在程序中可以直接使用这三个流,不需要调用 fopen()

可以发现这三个标准流和fopen的返回值都是FILE,文件指针。后续会进行讲解。

2-6. 打开文件的方式

C 语言中使用 fopen() 打开文件时,可选模式包括:

  • “r”:只读模式,文件必须存在。
  • “w”:只写模式,文件存在则清空,不存在则创建。
  • “a”:追加模式,写入时追加到文件末尾,文件不存在则创建。
  • “r+”:读写模式,文件必须存在,不会清空原文件内容,写入操作从文件开始覆盖。
  • “w+”:读写模式,文件存在则清空,不存在则创建。
  • “a+”:读写模式,写入操作始终追加到文件末尾,但可读取整个文件内容。

对于二进制文件,需在模式字符串中添加字母 “b”(如 “rb”, “wb”, “ab+” 等)。


总结

本文从狭义与广义两方面深入探讨了 Linux 中的“文件”概念,阐释了文件操作的分类及系统底层实现——包括文件描述符、inode、缓冲机制等。随后,通过 hello.c 案例详细回顾了 C 语言文件接口的使用方法,从文件的打开、写入、读取,到如何利用各种标准流(stdin、stdout、stderr)输出信息,以及不同的文件打开模式。希望本文能为大家在 Linux 基础 IO 学习及 C 语言文件操作实践中提供清晰的指导和帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/18450.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国产编辑器EverEdit - 二进制模式下观察Window/Linux/MacOs换行符差异

1 换行符格式 1.1 应用场景 稍微了解计算机历史的人都知道&#xff0c; 计算机3大操作系统&#xff1a; Windows、Linux/Unix、MacOS&#xff0c;这3大系统对文本换行的定义各不相同&#xff0c;且互不相让&#xff0c;导致在文件的兼容性方面存在一些问题&#xff0c;比如它们…

设计模式Python版 命令模式(下)

文章目录 前言一、命令队列的实现二、撤销操作的实现三、请求日志四、宏命令 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&…

Linux:进程概念详解

​ 进程概念详解 一、进程的基本概念 进程在书本上的定义是&#xff1a;计算机中正在运行的程序实例。仅此描述可能让很多人感到困惑。 我们磁盘上存储着.exe文件&#xff0c;启动文件时&#xff0c;文件会从磁盘加载到内存&#xff0c;由CPU对文件的数据和代码进行运算。但…

04性能监控与调优篇(D1_学习前言)

目录 一、引言 二、基本介绍 三、JVM基础 1. java堆 2. 垃圾回收 3. STW 四、调优层次 五、调优指标 六、JVM调优原则 1. 优先原则 2. 堆设置 3. 垃圾回收器设置 1> GC 发展阶段 2> G1的适用场景 3> 其他收集器适⽤场景 4. 年轻代设置 5. 年⽼代设置 …

系统思考—慢就是快

“所有成长&#xff0c;都是一个缓慢渗透的过程&#xff0c;回头看&#xff0c;才发现自己已经走了很远。” —— 余秋雨 这让我想起一个最近做的项目。和一家公司合作&#xff0c;他们的管理模式一直陷入困境&#xff0c;员工积极性低&#xff0c;领导层的决策效率也不高。刚…

String常量池(2)

大家好&#xff0c;今天我们继续学习String常量池&#xff0c;昨天我们已经做了一个介绍&#xff0c;相信大家✓String常量池有了一定了解&#xff0c;那么就来看看它的应用。 字符串常量地(String Table). 字常量她在IVM中是StringTable类,实际是一个固定大小的 HashTable(一…

LabVIEW显微镜成像偏差校准

在高精度显微镜成像中&#xff0c;用户常常需要通过点击图像的不同位置&#xff0c;让电机驱动探针移动到指定点进行观察。然而&#xff0c;在实际操作中&#xff0c;经常会遇到一个问题&#xff1a;当点击位于图像中心附近的点时&#xff0c;探针能够相对准确地定位&#xff1…

Typora“使用”教程

文章目录 零、Typora简介一、下载并安装Typora二、修改License文件三、每次启动第一个Typora时&#xff0c;总弹出Activate窗口四、去除软件左下角未Activate提示五、参考文章 零、Typora简介 Typora 是一款由 Abner Lee 开发的轻量级 Markdown 编辑器&#xff0c;与其他 Mark…

【scikit-multiflow】使用 scikit-multiflow 的流数据生成器生成概念漂移数据流

说在前面 scikit-multiflow 是一个专注于多流学习&#xff08;multi-stream learning&#xff09;的Python库&#xff0c;它为数据流挖掘和在线学习提供了丰富的工具集。这个库的设计灵感来源于著名的scikit-learn&#xff0c;旨在为研究人员和从业者提供一个易于使用且功能强…

计算机视觉-局部特征

一、局部特征 1.1全景拼接 先用RANSAC估计出变换&#xff0c;就可以拼接两张图片 ①提取特征 ②匹配特征 ③拼接图像 1.2 点的特征 怎么找到对应点&#xff1f;&#xff08;才能做点对应关系RANSAC&#xff09; &#xff1a;特征检测 我们希望找到的点具有的特征有什么特…

matlab下载安装图文教程

【matlab介绍】 MATLAB是一款由美国MathWorks公司开发的专业计算软件&#xff0c;主要应用于数值计算、可视化程序设计、交互式程序设计等高科技计算环境。以下是关于MATLAB的简要介绍&#xff1a; MATLAB是MATrix LABoratory&#xff08;矩阵实验室&#xff09;的缩写&#…

Whisper+T5-translate实现python实时语音翻译

1.首先下载模型&#xff0c;加载模型 import torch import numpy as np import webrtcvad import pyaudio import queue import threading from datetime import datetime from faster_whisper import WhisperModel from transformers import AutoTokenizer, AutoModelForSeq2…

Python微博动态爬虫

本文是刘金路的《语言数据获取与分析基础》第十章的扩展&#xff0c;详细解释了如何利用Python进行微博爬虫&#xff0c;爬虫内容包括微博指定帖子的一级评论、评论时间、用户名、id、地区、点赞数。 整个过程十分明了&#xff0c;就是用户利用代码模拟Ajax请求&#xff0c;发…

爬虫实战:利用代理ip爬取推特网站数据

引言 亮数据-网络IP代理及全网数据一站式服务商屡获殊荣的代理网络、强大的数据挖掘工具和现成可用的数据集。亮数据&#xff1a;网络数据平台领航者https://www.bright.cn/?promoRESIYEAR50/?utm_sourcebrand&utm_campaignbrnd-mkt_cn_csdn_yingjie202502 在跨境电商、社…

2.认识标签和去标签|下载boost库|建立项目结构

下载Boost库 Boost C Libraries 选择右边的Documentation 选择最新的1.87.0版本 可以在首页的这里下载最新版本 建立项目结构 新建目录boost_searcher mkdir boost_searcher移动到boost_searcher目录 cd boost_searcher下载rz命令 yum install lrzsz导入boost文件&…

Transformer 模型介绍(三)——自注意力机制 Self-Attention

Transformer 模型由 Vaswani 等人于2017年提出&#xff0c;主要应用于序列到序列的任务&#xff0c;最初应用于机器翻译。其核心思想是通过自注意力机制捕捉序列中的长期依赖关系&#xff0c;从而有效地进行任务建模 在著名的论文《Attention Is All You Need》中&#xff0c;…

《AI大模型开发笔记》Open-R1:对 DeepSeek-R1 的完全开源再现(翻译)

Open-R1&#xff1a;对 DeepSeek-R1 的完全开源再现&#xff08;翻译&#xff09; 原文链接&#xff1a;https://huggingface.co/blog/open-r1 什么是 DeepSeek-R1&#xff1f; 如果你曾经为一道艰难的数学题苦思冥想&#xff0c;那么你就知道花更多时间、仔细推理是多么有用…

Java虚拟机面试题:JVM调优

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

每日Attention学习23——KAN-Block

模块出处 [SPL 25] [link] [code] KAN See In the Dark 模块名称 Kolmogorov-Arnold Network Block (KAN-Block) 模块作用 用于vision的KAN结构 模块结构 模块代码 import torch import torch.nn as nn import torch.nn.functional as F import mathclass Swish(nn.Module)…

Centos安装php-8.0.24.tar

查看系统环境 cat /etc/redhat-release 预先安装必要的依赖 yum install -y \ wget \ gcc \ gcc-c \ autoconf \ automake \ libtool \ make \ libxml2 \ libxml2-devel \ openssl \ openssl-devel \ sqlite-devel yum update 1、下载解压 cd /data/ wget https:/…