【Linux】文件管理

ops/2025/2/21 8:42:44/

在这里插入图片描述

个人主页~


文件管理

  • 一、回顾C文件管理
  • 二、系统文件IO
    • 0、序
    • 1、open函数
      • flags标识位的方法
    • 2、文件描述符fd
    • 3、重定向
      • (一)dup2
      • (二)标准输出vs标准错误

一、回顾C文件管理

有关于c文件操作的详细内容可阅拙作《C语言文件操作》

特别指出的是,文件写函数我们重点要讨论,关于文件读的函数我们会用就行,因为没有什么其他可以谈的

关于fopen("text.txt","w");fwrite(message,strlen(message),1,fp);的使用,文件的写
在这里插入图片描述
在这里插入图片描述
关于fread(buf,1,strlen(message),fp);的使用,文件的读
在这里插入图片描述

在这里插入图片描述
还有一个我们要注意的是,使用C的时候,我们的文件默认会打开三个流,分别是stdin标准输入流、stdout标准输出流、stderr标准错误流

二、系统文件IO

0、序

我们已经学完了Linux三大金刚之一的进程,现在我们来学习同为Linux三大金刚之一的文件系统相关的内容,我们知道,进程的管理是先描述后组织,我们推己及人一下,这里对于文件系统的管理当然也是先描述后组织,我们也有一个结构体来管理文件

1、open函数

在这里插入图片描述
open函数有两个版本,上面那个和下面这个差了一个参数,我们主要讲下面这个版本

int open(const char *pathname, int flags, mode_t mode);
//pathname:打开或创建的目标文件名//flags:打开文件时的参数(前三个必须要选一个)
//O_RDONLY: 只读打开
//O_WRONLY: 只写打开
//O_RDWR  : 读,写打开//O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
//O_APPEND: 追加写
//O_TRUNC : 如果文件已经存在,并且以可写模式打开,则将文件长度截断为 0,即清空文件内容//mode:设定新文件的访问权限//返回值:成功为新打开的文件描述符fd,失败为-1

一般来说,如果我们使用open的时候新创建文件就要用下面那个open,如果我们对已有文件进行打开,那么我们用上面那个open

下面我们来使用一下open系统调用,以只写模式并且在目标文件没有的情况下创建一个myfile文件,文件权限为0666,然后定义一个字符串message,使用write(fd,message,len);作用是将message中的len个字节写到fd所指向的对象,也就是刚刚open的目标文件
在这里插入图片描述
myfile文件被创建并写入
在这里插入图片描述
这里新创建的文件权限为0664,因为我们对应的文件掩码umask为2
在这里插入图片描述

这里我们在C语言文件中的f开头的函数,例如fopen啦、fwrite啦其实都是对系统调用open、write等的封装

flags标识位的方法

这里的flags标识位用的是二进制标识,这是我们常用的一种标识方式,通过按位或 | 的方式来进行组合

标志位八进制值二进制表示(假设为 16 位整数)含义
O_RDONLY000000 0000 0000 0000只读模式
O_WRONLY010000 0000 0000 0001只写模式
O_RDWR020000 0000 0000 0010读写模式
O_CREAT01000000 0001 0000 0000如果文件不存在则创建
O_EXCL02000000 0010 0000 0000与 O_CREAT 联用,若文件已存在则打开失败
O_TRUNC010000000 1000 0000 0000若文件存在则截断为长度 0
O_APPEND020000001 0000 0000 0000追加模式
O_NONBLOCK040000010 0000 0000 0000非阻塞模式

这样我们可以看到,每个比特位代表着一个状态,假设二进制表示为16位整数后四位代表着文件读写状态,前八位表示这文件打开的附加选项

通过按位或 | ,我们可以将我们需要的选项全部搞到一个数字上,例如我们open("myfile", O_WRONLY|O_CREAT, 0666);这里的flags==0000 0001 0000 0001

2、文件描述符fd

我们将收到的文件描述符全部打印看一下效果
在这里插入图片描述

在这里插入图片描述

我们发现这好像有点顺序啊,只要open成功打开,fd就必然是大于等于0的数字,我们第一个打开的文件是3,第二个是4,那么我们的0,1,2去哪了?

其实我们的0就是标准输入,1标准输出,2标准错误,对应的硬件设备分别是0为键盘,1,2为显式屏,举一个简单的例子,我们在打开电脑的时候Windows操作系统是不是先给我们连上键盘和显示屏呢

我们程序访问文件,实际上就是进程访问文件,我们的进程PCB有指向files_struct的指针*files,而我们的files_struct中有一个数组fd_array用来存放我们的文件描述符,其中012默认调用的,其他的3456指向我们的新打开的各个文件,本质上文件描述符就是该数组的下标

我们进程在进行open系统调用的时候,就会找到files指针然后拿到我们对应的fd_array的位置然后默认打开012,然后打开我们的myfile1等我们的文件

打开的文件会在内核创建一个file对象,存储比如文件的读写位置,文件的访问模式,文件操作函数指针,对底层文件系统或设备的引用等关键信息,这里说明一下,open函数的核心任务之一就是将用户指定的访问模式写入内核的file结构体
在这里插入图片描述
文件描述符的分配原则:在fd_array中找到一个没有被使用的最小下标,比如我们打开fd为3,4,5的三个文件,我们将fd为4的文件关闭后新建文件打开,此时这个新建的被打开打开的文件的fd为4

3、重定向

我们说fd==1对应的是标准输出,也就是屏幕,那么我们将这个标准输出关掉,会发生什么呢
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
我们发现,这里标准输出被关掉了,程序的打印果然没有打印到屏幕上,并且我们都fflush刷新缓冲区了,说明打印的信息也不再缓冲区里,而且我们发现,这个程序如果不关闭1的话,打印到文件中的信息应该是打印在屏幕上的,为啥打印到文件中了呢?

我们在前面文件描述符的分配原则中说过,新文件会被整个数组中一个最小的fd指向,close就是将1置为NULL,然后open函数被调用,mytext自然的被分配给了1,此时fd==1,打印出来的fd自然也是1,不过是打印到了mytext文件中,这就是输出重定向
在这里插入图片描述
当然这是被动的重定向,如果我们不想去关掉标准输出,又想进行重定向呢
通过系统调用接口dup2就可以实现

(一)dup2

#include <unistd.h>int dup2(int oldfd, int newfd);
//你可以把比作一个复制函数
//这个函数被复制的是oldfd,最后两个值都是oldfd

在这里插入图片描述

在这里插入图片描述
我们逐句分析,先open mywork,此时0->标准输入,1->标准输出,2->标准错误,3->mywork,然后将1关掉就是0->标准输入,1->NULL,2->标准错误,3->mywork,然后使用dup2将3复制到1,就是0->标准输入,1->mywork,2->标准错误,3->mywork,此时不管是用printf函数还是fprintf函数,所打印的内容全部都会打印到mywork文件当中

这里有几个值得注意的地方:
①dup2的使用,是将3位置的指针拷贝到1位置,让1和3共同指向mywork
②printf是C库当中的IO函数,一般往stdout中输出,但是stdout底层访问文件的时候,找的还是fd:1, 但此时,fd:1下标所表示内容,已经变成了myfile的地址,不再是显示器文件的地址
③由②引申出来的:显示屏也是文件,Linux下一切皆文件

(二)标准输出vs标准错误

通过学习上面的内容我们知道,标准输出和标准错误都可以将信息打印到屏幕上,它们俩有什么区别呢?答案就是除了默认情况下,它们的fd值不同,其他都一样

它们两个都指向显示器,只是我们比较习惯用两个支流,一个用来正常工作,另一个用来打印错误信息所以他们本质上是没有什么区别的

看看小区别
在这里插入图片描述
这里的命令应该比较容易看懂,就是打印到stdout流的也就是1中的内容打印到normal.txt文件当中,打印到stderr流的也就是2中的内容打印到err.txt当中
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
我们分解开来看这条命令:

./myproc这部分表示执行当前目录下名为 myproc 的可执行程序,在 Linux 中,当前目录并不在默认的可执行文件搜索路径中,所以如果要执行当前目录下的程序,需要显式地使用 ./ 来指定程序所在的路径

1>all.txt重定向符号 >:> 是输出重定向符号,它的作用是将命令的输出内容从默认的标准输出重定向到指定的文件中,1> 明确表示将标准输出进行重定向,重定向的目标文件为 all.txt,如果该文件不存在,系统会自动创建它;如果文件已经存在,其原有内容会被新的输出内容覆盖

2>&1重定向符号 &>:& 在这里是一个特殊的符号,用于引用文件描述符,2>&1 的意思是将标准错误输出重定向到和标准输出相同的地方,结合前面的 1>all.txt,就是把标准错误输出也重定向到 all.txt 文件中

这里先输出标准错误信息的原因是:标准错误一般输出没有缓冲区,而标准输出是有缓冲区的,而它们并没有谁先谁后的定性要求,所以标准输出搁缓冲区里缓冲了一下当然要稍微慢一点了


今日分享就到这里啦~
在这里插入图片描述


http://www.ppmy.cn/ops/160193.html

相关文章

Visual Studio Code 集成 Baidu Comate

文章目录 安装Baidu Comate插件 安装Baidu Comate插件 从左主侧栏中 点击 【扩展】这个图标&#xff0c;然后在上方输入栏中输入 baidu comate —>选中列出的Bai Comate —>点击 【安装】按钮&#xff0c;等待安装完毕…

rust学习六、简单的struct结构

一、结构定义 struct-翻译为结构/结构体 总体上有两种定义方式&#xff1a;带有详细属性名的&#xff1b;不带属性名&#xff08;元组&#xff09; 从工程角度出发&#xff0c;并不推荐不带属性的定义方式&#xff0c;因为不友好。希望rust后面不要搞类似好像很友好&#xff…

汉化VScode

第一步 打开开发工具, 点扩展按钮 第二步 在输入框内输入Chinese 第三步 点击(Chinese)中文插件 第四步 点击 install(安装) 安装好后, 关掉开发工具, 重新打开, 就汉化成功了 .

《DAMA数据管理知识体系指南》第一章 数据管理读书笔记

《DAMA数据管理知识体系指南》第一章 数据管理读书笔记 《DAMA数据管理知识体系指南》第一章围绕数据管理展开多方面论述,涵盖DAMA与DMBOK概述、数据管理基础概念、原则、挑战、战略及框架等内容,为数据管理专业人员提供全面指导,对理解和实践数据管理意义重大。 一、DAMA…

洛谷 P10726 [GESP202406 八级] 空间跳跃 C++ 完整题解

一、题目链接 P10726 [GESP202406 八级] 空间跳跃 - 洛谷 二、解题思路 我们要对输入的挡板进行排序&#xff0c;按高度从高到低&#xff08;从小到大&#xff09;。 排序之后s和t都要更新。 struct Baffle {int l, r;int h;int id; } b[1005];void Sort() {sort(b 1, b 1 n…

本地部署MindSearch(开源 AI 搜索引擎框架),然后上传到 hugging face的Spaces——L2G6

部署MindSearch到 hugging face Spaces上——L2G6 任务1 在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下&#xff0c;Space 名称中需要包含 MindSearch 关键词&#xff0c;请在必要的步骤以及成功的对话测试结果当中 实现过程如下&#xff1a; 2.1 MindSearch 简…

qt:常见标签操作,倒计时功能,进度条与日历

1.标签常见函数 函数功能void setext(const QString &text)设置文本QString text()const获取文本void setPixmap(const QPixmap)与Pixmap()const设置和获取图像void setAlignment(Qt::Alignment alignment)设置对齐&#xff08;获取和上面一样&#xff09;void setWordWr…

DeepSeek+kimi自动生成ppt

AI自动生成ppt 描述需求&#xff0c;生成大纲 在deepseek里输入需求&#xff0c;https://chat.deepseek.com/&#xff0c; 或者在其它AI搜索里&#xff0c;如kimi中Kimi.ai - 会推理解析&#xff0c;能深度思考的AI助手 搜索后会得到大纲&#xff0c;复制出来。 打开KIMI …