【文件fd】回顾C语言文件操作 | 详细解析C语言文件操作&写w&追加a | 重定向和“w““a“

目录

前言

回顾C语言的操作

Q1

Q2 

Q3 

C语言文件操作

w方式

a方式

重定向和"w""a"方式


前言

前面进程虚拟地址空间让我们对进程的理解更加深入。在基础IO我们会详细介绍文件和文件系统。本专题的核心内容是文件。

  • 深刻理解文件(站在OS的角度)
  • 深入理解重定向和缓冲区
  • 学习文件系统(磁盘文件和经典的文件系统结构)
  • 以及动静态库制作和使用,yum源的配置等操作。

回顾C语言的操作

❓在C语言阶段,我们学习了C语言是如何打开/关闭/写入/读取文件的。我们仅仅是在语言层面上学会了对文件的操作接口。不仅C/C++/Java等其他语言都有文件操作接口,文件操作都不一样,为什么不一样。

❓是否我们站在OS的角度就可以理解文件。

请看以下代码☞,思考下面问题: 

 1: testfile.c                                                                               
  1 #include<stdio.h>
  2 int main()
  3 {
  4   FILE *fd = fopen("log.txt","w");                                                                           
  5   if(fd == NULL)
  6   {
  7     perror("fopen");
  8     return 1;
  9   }
 10   fclose(fd);
 11   return 0;
 12 }

//运行可执行程序,文件不存在,OS默认创建在当前目录下

【文件指针FILE】  

【perror】

Q1

❓创建一份C语言的文件时,并没有指明文件的具体路径,代码中只是告知文件名,OS怎么知道当前创建的文件在我们想要的路径下呢。

回答:因为我们在运行我们的程序的时候,执行打开文件操作的代码的时候。 程序已经变成一个进程。所以我们创建log.txt文件时,默认会结合当前进程所在路径创建,所以如何没有路径给到OS,那么OS会结合进程当前所在路径去创建log.txt。 

❓我们写完文件操作的代码,fopen文件就算被打开了吗。

回答:文件操作的代码写完了。但是不编译运行。文件根本没有被打开。我们要进行文件操作,前提是我们的程序跑起来了,成为进程了。文件打开和关闭,是CPU在调度我们的进程,正好执行到fopen和fclose代码。打开文件的本质其实是进程打开文件!!

【进程在启动时所处的路径叫进程的当前工作路径】

Q2 

❓文件没有被打开的时候在哪里。在磁盘上

❓一个进程能打开很多文件吗。可以

❓系统中能存在很多进程吗。很多情况下,在OS内部,一定存在大量的被打开的文件。

❓OS需要对大量的文件做管理吗。肯定的。

没有被打开的文件在磁盘(硬件上),如果需要打开文件,就需要访问硬件。硬件的管理者是操作系统。一定是OS打开文件。OS打开大量的文件,就需要把这些打开的文件进行管理。(管理的六字真言:先描述再组织)

❓先描述再组织。意味着:在OS内部,也要创建文件对应对象-内核数据结构,打开文件,创建数据结构,形成很多文件对象。最后以链表的形式管理起来。对文件的管理,变成对链表的增删查改。(每一个被打开的文件,在OS内部,一定要存在对应的描述文件属性的结构体。类似PCB)

  • struct PCB(task_struct):可执行程序加载到内存中,可执行程序的内核数据结构
  • struct RunQueue:硬件有对应的等待队列
  • struct file:文件也有对应的内核数据结构(存放文件属性)
  • OS内核中一个被打开的文件本质一定是一个文件对象或者一个结构体类型的对象。
  • struct task_struct☞struct file两种对象之间的指针关系 

Q3 

 ❓新建一个大小为0的文件在磁盘需不需要占据磁盘空间。(文件没有打开,没有在内存中,在磁盘中)

回答:要占磁盘空间。文件名/时间/类型/大小/权限等文件属性等都是数据,需要占据磁盘空间。文件 = 文件属性 + 文件内容

C语言文件操作

w方式

以w方式打开文件。

  • w方式的特点:
  1. 文件存在,就清空写入
  2. 文件不存在,在当前进程的工作目录路径下创建,写入。
  3. 默认打开文件的时候,就会先把目标文件清空!
  • 写入库函数接口:fprintf
  • man fprintf
  • int fprintf(FILE *stream, const char *format, ...);
  • FILE *stream:写入指定的文件
  • const char *format, ...:以指定格式把指定内容写入
  • w      Truncate  file  to zero length or create text file for writing.

打开创建当前文件。进程被调度,执行到代码语句的时候,才会打开,写入,判断,关闭等系列文件操作(进程被调度)。里面含有/proc进程的当前工作路径。

 【文件存在,就清空写入】

【清空实验】

在存在log.txt文件且log.txt内容存在的情况下。只有打开,没有写入和关闭。我们再以w的方式打开一次文件。

原log.txt存在数据,但再以写的方式打开一次(只打开)。文件仍然存在,默认文件的内容被清空。在C语言,以w属性打开文件,文件打开即清空。

【文件不存在,在当前进程的工作目录路径下创建,写入】

a方式

以a方式打开文件。

  • a方式的特点:
  1. 文件存在,就不清空写入
  2. 文件不存在,在当前进程的工作目录路径下创建,写入。
  3. 默认打开文件的时候,就不会先把目标文件清空!
  • 文件存在且有内容的情况下,重新打开文件,写入。w方式一定会清空文件再写入;而a方式不会清空直接追加。
  • appending追加:追加的本质也是写到文件的结尾。

 【文件存在,就清空写入】

【文件不存在,在当前进程的工作目录路径下创建,写入】 

重定向和"w""a"方式

重定向回顾:

使用重定向可以极大地提高Linux命令行操作的灵活性和效率,尤其是在脚本编写和自动化任务中。

 请看下面代码☞:

  • echo "hello linux" Linux当中一切皆文件默认向显示器文件stdout打印
  • > 输出重定向本质就是把向显示器文件写入的数据,重定向向log.txt文件写入
  • 经过重定向变成了本来应该向显示器打印的内容,写入了磁盘文件中
  • 经过上面分析,我们猜测重定向一定伴随文件操作或者和文件操作有关。
  • 输出重定向一定是文件操作!

  • > 的特点:每次写入文件的数据都是存在文件,清空写入;不存在,创建写入。(每次写入都要清空)
  • 所以,推测> 是以 "w" 方式把文件打开。
  • > 可以用来新建文件,清空文件。(不存在就创建。先清空,再写入)
  • >> 的特点:存在文件,不清空写入;不存在,创建写入。
  • 所以,推测>> 是以"a"方式把文件打开。

【>】 

【>>】

🙂感谢大家的阅读,若有错误和不足,欢迎指正。

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,您的问题是如何用C语言模拟shell并实现输入输出重定向。 首先,需要使用系统调用来实现模拟shell所需的功能。具体来说,需要使用fork()函数创建子进程,使用exec()函数来执行外部命令,使用wait()函数等待子进程结束并回收资源。 对于输入输出重定向,可以使用dup2()函数将文件描述符重定向到指定的文件或设备上。例如,可以使用dup2()函数将标准输入或标准输出重定向文件中,实现输入输出文件重定向的功能。 下面是一个简单的示例程序,演示如何实现输入输出重定向: ``` #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main() { char cmd[1024]; int fd_in, fd_out; pid_t pid; while (1) { printf("myshell> "); fgets(cmd, 1024, stdin); // 检查是否需要重定向输入 if ((fd_in = open("input.txt", O_RDONLY)) != -1) { dup2(fd_in, STDIN_FILENO); close(fd_in); } // 检查是否需要重定向输出 if ((fd_out = open("output.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644)) != -1) { dup2(fd_out, STDOUT_FILENO); close(fd_out); } // 创建子进程并执行命令 if ((pid = fork()) == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { system(cmd); exit(EXIT_SUCCESS); } // 等待子进程结束并回收资源 waitpid(pid, NULL, 0); } return 0; } ``` 在上面的示例程序中,我们使用了open()函数打开文件,并使用dup2()函数将文件描述符重定向到标准输入或标准输出上。注意,在使用open()函数打开文件时,需要指定相应的标志来指定文件的读模式。 以上是一个非常简单的示例程序,实际上,模拟shell需要考虑的问题很多,比如如何处理管道、如何实现后台执行等等。但是,本文无法一一说明,希望以上内容能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐唐思

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值