[操纵体系] 基础 IO:明白“文件”与 C 接口

打印 上一主题 下一主题

主题 998|帖子 998|积分 2994



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


明白“文件”

1-1. 狭义明白

在狭义上,“文件”通常指存储在磁盘中的普通文件。它是由字节(或字符)序列构成的数据集合,在磁盘上以肯定的结构保存(如 FAT、ext4 等文件体系)。使用狭义概念时,我们关注的是文件的内容、巨细、权限等属性。比方,一个存放文本数据的文件或一个二进制文件,都可以被看作传统意义上的“文件”。文件对外设的输入输出简称IO。
   示例代码(仅演示概念,不涉及实际操纵):
  1. // 假设 f1.txt 是一个普通文本文件
  2. FILE *fp = fopen("f1.txt", "r");  // 以只读方式打开文件
  3. if (fp == NULL) {
  4.     perror("打开文件失败");
  5.     exit(EXIT_FAILURE);
  6. }
  7. // 读取或处理文件...
  8. fclose(fp);
复制代码
1-2. 广义明白

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


  • 设备文件:包括字符设备、块设备,代表硬件(如键盘、显示器、硬盘);
  • 管道和套接字:用于进程间通讯;
  • 目录:虽然目录本质上是特别类型的文件,但它们存储的是文件名和相干元数据;
  • 虚拟文件:比方 /proc 下的各种伪文件,用于显示内核和进程状态。
这种广义的明白使得操纵体系将各种资源同一为文件接口,步调员在操纵时无需关心底层硬件的细节,只需通过同一的读写操纵即可。
1-3. 文件操纵的归类认知

   文件是文件属性(元数据)文件内容的集合,文件 = 属性 + 内容。
  所以所有的文件操纵都是对文件内容或者对文件属性操纵。
  文件操纵大要可以分为以下几类:


  • 序次读写:文件数据按序次读取和写入。
  • 随机访问:通过定位(如 lseek)在文件中跳转到恣意位置进行读写。
  • 标准流操纵:通过 C 标准库的 fopen、fread、fwrite、fseek、fclose 等接口操纵文件,这是一种缓冲 IO 方式,适用于大多数应用步调。
  • 体系调用接口:使用 open、read、write、lseek、close 等体系调用,直接与内核交互,具有更低的开销和更高的机动性,但使用较为复杂。
通过这样的分类,我们可以根据实际需求选择合适的接口。
1-4. 体系角度


  • 对文件的操纵本质上是进程对文件的操纵。
  • 磁盘管理者是操纵体系,操纵体系对打开的文件管理的方式是:先描述,后构造
  • 文件读写的本质不是通过各种语言的库函数来操纵完成的,上层语言知识为了给用户提供方便,而是通过文件相干的体系调用来实现的。

回顾 C 文件接口

2-1. hello.c 打开文件

在 C 语言中,使用 fopen() 打开文件。函数原型如下:
  1. FILE *fopen(const char *filename, const char *mode);
复制代码
此中,filename 表示文件名(可包含路径),mode 指定打开模式(如 “r”、“w”、“a” 等)。
   示例代码:
  1. // hello.c —— 打开文件示例
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main(void) {
  5.     FILE *fp = fopen("hello.txt", "w+"); // 以读写方式打开,如果文件不存在则创建,存在则清空
  6.     if (fp == NULL) {
  7.         perror("打开文件失败");
  8.         exit(EXIT_FAILURE);
  9.     }
  10.     printf("文件打开成功,文件指针:%p\n", fp);
  11.     fclose(fp);
  12.     return 0;
  13. }
复制代码
2-2. hello.c 写文件

写文件操纵可以使用 fwrite()、fputs()、fprintf()、fputc() 等接口。这里以 fputs() 为例:
  1. fputs("Hello, Linux IO!\n", fp);
复制代码
或者使用 fprintf() 进行格式化输出:
  1. fprintf(fp, "数字:%d,字符串:%s\n", 123, "abc");
复制代码
  示例代码:
  1. // hello.c —— 写文件示例
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main(void) {
  5.     FILE *fp = fopen("hello.txt", "w+");
  6.     if (fp == NULL) {
  7.         perror("打开文件失败");
  8.         exit(EXIT_FAILURE);
  9.     }
  10.     // 使用 fprintf 写入数据
  11.     fprintf(fp, "Hello, Linux IO!\n");
  12.     // 使用 fputs 写入字符串
  13.     fputs("这是通过 fputs 写入的一行文字。\n", fp);
  14.     fclose(fp);
  15.     return 0;
  16. }
复制代码
新文件的创建路径

<font style="color:rgb(31,35,41);">ls /proc/[进程id] -l</font>可以检察当前运行进程的信息。
  1. [@VM-8-12-centos io]$ ps ajx | grep myProc
  2. 506729 533463 533463 506729 pts/249 533463 R+ 1002 7:45 ./myProc
  3. 536281 536542 536541 536281 pts/250 536541 R+ 1002 0:00 grep --
  4. color=auto myProc
  5. [@VM-8-12-centos io]$ ls /proc/533463 -l
  6. total 0
  7. ......
  8. -r--r--r-- 1  0 Aug 26 17:01 cpuset
  9. lrwxrwxrwx 1  0 Aug 26 16:53 cwd -> /home/ddd/io
  10. -r-------- 1  0 Aug 26 17:01 environ
  11. lrwxrwxrwx 1  0 Aug 26 16:53 exe -> /home/ddd/io/myProc
  12. dr-x------ 2  0 Aug 26 16:54 fd
复制代码
此中:
   cwd:指向当进步程运⾏⽬录的⼀个符号链接,当进步程中创建文件的默认相对路径。
  exe:指向启动当进步程的可执⾏⽂件(完整路径)的符号链接。
  每个进程在运行时都有一个当前工作目录(CWD),这是进程在文件体系中的“当前位置”。当进程打开一个文件时,如果文件路径是相对路径(即不以 / 开头),操纵体系会默认将这个路径剖析为相对于进程的当前工作目录。
2-3. hello.c 读文件

读文件操纵常用的接口包括 fread()、fgets()、fgetc()。比方,使用 fgets() 逐行读取文件:
  1. char buffer[256];
  2. while (fgets(buffer, sizeof(buffer), fp) != NULL) {
  3.     printf("%s", buffer);
  4. }
复制代码
  示例代码:
  1. // hello.c —— 读文件示例
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main(void) {
  5.     FILE *fp = fopen("hello.txt", "r");
  6.     if (fp == NULL) {
  7.         perror("打开文件失败");
  8.         exit(EXIT_FAILURE);
  9.     }
  10.     char buffer[256];
  11.     while (fgets(buffer, sizeof(buffer), fp) != NULL) {
  12.         printf("%s", buffer);
  13.     }
  14.     fclose(fp);
  15.     return 0;
  16. }
复制代码
稍加改动即可模拟cat下令。
  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(int argc, char* argv[]) {
  4.     // 检查命令行参数数量是否正确
  5.     if (argc != 2) {
  6.         printf("argv error!\n");
  7.         return 1;
  8.     }
  9.     // 打开文件
  10.     FILE *fp = fopen(argv[1], "r");
  11.     if (!fp) {
  12.         printf("fopen error!\n");
  13.         return 2;
  14.     }
  15.     // 定义缓冲区
  16.     char buf[1024];
  17.     // 循环读取文件内容
  18.     while (1) {
  19.         int s = fread(buf, 1, sizeof(buf), fp);
  20.         if (s > 0) {
  21.             // 确保字符串以空字符结尾
  22.             buf[s] = '\0';
  23.             printf("%s", buf);
  24.         }
  25.         if (feof(fp)) {
  26.             break;
  27.         }
  28.     }
  29.     // 关闭文件
  30.     fclose(fp);
  31.     return 0;
  32. }
复制代码
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 语言文件操纵实践中提供清晰的指导和资助。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表