目录
引言
Linux操作系统以其强大的稳定性、灵活性和开放性在多个领域占据重要地位。在Linux系统中,文件和目录构成了系统数据结构的基础,它们不仅存储着系统的配置信息、应用程序以及用户数据,而且在系统管理、资源共享和数据保护方面发挥着关键作用。因此,对于Linux用户,尤其是工程师和系统管理员来说,熟练掌握Linux文件和目录的管理技巧是不可或缺的。
本文将通过
以下三个话题,走进linux文件管理。
基础知识
1.学习文件管理,需要先具备一些基础知识。
2.一个文件被打开,必须加载到内存,并且一个进程可以打开多个文件。
在OS内部,一定存在大量被打开的文件,OS必须去管理这些文件----先描述再组织-----在内核中,一个被打开的文件,都必须有一个结构对象去管理这个文件。
3.std : 标准 I/O:输入输出
回顾C语言
fopen
fopen在stdio中io表示标准的输入输出,fopen用于打开一个文件。
第一个参数是:路径 (default : 当前目录下)+ 文件名
第二个参数是: 打开方式
需要特别注意的是,只要用w方式打开,无论何种方式,总是会先清空文件内容!
需要注意的是:两个参数都是const char*
fclose
文件资源打开后需要手动关闭!FILE* fp是文件指针
打开路径默认是当前路径,当前路径是什么呢?
我们可以在/proc中查看
如果打开一个进程,cwd就是当前路径。
同理,我们更改了cwd,就可以改变文件的默认创建路径。
更改进程路径:chdir
fwrite可以用来写入
(fprintf也可以,fprintf写入也遵循fread的打开方式)
fwrite 函数在写入时会从文件的当前指针位置开始覆盖数据,而不是清空整个文件
四个参数为:内容、大小、写入个数、写入哪个文件夹。
不需要 + 1,对于C而言/0是字符串的结尾,但是对于文件而言,不需要让/0作为字符串的结尾。
sizeof字符串
在C语言中,sizeof运算符用于确定一个数据类型或变量在内存中所占用的字节数。当使用sizeof来获取一个字符串的大小的时候,它计算的是字符串的字符数组总的字节大小,包括结尾的空字符\0。
例如,如果你有一个字符串"Hello",它在内存中实际上是一个字符数组{'H', 'e', 'l', 'l', 'o', '\0'}。因此,如果你使用sizeof来获取这个字符串的大小,你会得到6,这6包括了5个字母和一个结尾的空字符。
这里有一个例子:
#include <stdio.h>
int main() {
char str[] = "Hello";
printf("Size of str: %zu\n", sizeof(str)); // 输出将包括 '\0' 的字节数
return 0;
}
如果str是一个字符数组并且是在栈上分配的,sizeof(str)会给出整个数组的大小,包括结尾的空字符\0。但是,如果你有一个指向字符串的指针,如下:
char *str = "Hello"; //在代码段
在这种情况下,sizeof(str)将会给出指针本身的大小,而不是字符串的大小。在32位系统上,这通常是4字节,在64位系统上,通常是8字节。要获取字符串的实际长度,你需要使用strlen函数,但是请注意strlen只计算到\0之前的字符数量,不包括\0本身。
在栈上的字符串sizeof = strlen + 1
当我们strlen(str) + 1时,会把/0也写进去,但是在vim中打开是乱码,这是因为在vim中某些字符也是不可显的
输出重定向(相对自身来说,内容是输出、是交出去,而不是输入):也是先清空
因此> 与>>的区别就是一个w一个a打开
当用a方式打开文件时,继续写入就是追加写入。
可见,写入的形式是清空重新写还是追加,由打开方式决定
C语言默认打开三个输入输出流
到后期就能明白,这三个输入输出流每种语言都会打开,只不过在C中的形式为std + in out err
C++为cin cout cerr
过渡到系统
我们读写一个文件,本质是对磁盘中的数据进行IO操作,磁盘是硬件。
想要访问硬件只能从上到下层层访问,必须经过OS,那就得用系统调用。
系统调用:open
有三个头文件
两个参数:路径(绝对或者相对)、打开方式
当文件存在时,用第一个打开
当文件不存在时,用第二个新建式的打开
参数二:
O_RDONLY,O_WEONLY,O_RDWR:分别为只读、只写、读写
O-APPEND为追加
O_CREAT为创建
“位字段”或“位掩码”
内部用按位与的逻辑,传参用按位或的逻辑
内部用 &的逻辑,由于32个比特中的数字除了0就是1,那么&之后,除非同一位的数字都为一,否则&之后变成0。外部用按位或的逻辑
按位与:只有都是1,才能变成1,想变成“真”的条件严格
按位或:只要有1,就能变成1,变成“真”的条件宽松
由于内部是if语句,当契合时,将调用对应的函数func。
open的第二个参数flags内部提供很多宏
宏里面只有一个bite为1,它可以传递多种标志位做按位或的组合,就能达到各种各样的效果(比如:只读、只写、读写、写创建、、、)
这种传参方式被称为“位字段”或“位掩码”(bit field 或 bit mask)。
在编程中,使用单个字节(或字)的每一位来表示不同的布尔选项或标志,是一种有效的内存使用技术。每个位可以独立地设置为0或1,代表不同的开关或配置选项,通过对这些位进行按位或操作(OR),可以同时传递多个标志。例如,在UNIX系统的文件权限设置中就使用了这种方式。
open的使用
返回一个文件描述符
失败返回 -1
当我们执行的时候,发现没有新建,也没有打开。
正确方式
但是我们发现权限信息是乱码
为什么不对呢?open新建一个文件时,必须说明新建的权限(第三个参数)
我们用8进制的形式,来传递文件权限。
这样就获得了正常的权限
需要注意的是:权限 = 权限掩码 和 设置的权限共同作用的结果
调用了umask函数,它会影响你的进程及其后续创建的任何子进程的文件和目录权限。在进程的上下文中,这相当于修改了该进程的默认文件权限掩码。(不修改其他文件)
Linux下的系统调用在Windows中通常无法直接运行
这样就变成了666
关闭文件:close
写入:write
向一个文件中写入大小为count的字符串。
这种写入方法是:写入默认从文件开始处开始写(覆盖写,不清空)
清空O_TRUNC:truncate:截断
这种打开方式为:写入、创建、清空
追加O_APPEND:append
现在为:写入、创建、追加
如果文件log.txt已经存在,使用O_CREAT标志并不会导致创建一个新的文件,而是会打开现有的文件。只有当log.txt不存在时,O_CREAT标志才会与给定的权限一起使用来创建这个文件。
因此,每次执行t1.exe时,如果log.txt已经存在,它将不会被重新创建,而是会被打开,并且任何写入操作都会在文件的末尾追加内容。如果文件不存在,它将会被创建。
OS文件管理
OS内部将描述一个文件的打开信息
struct file结构
当我们打开多个文件,OS管理文件时,对文件链表的增删查改
文件被进程打开,如何知道哪个进程打开哪个文件呢?struct file 与 pcb的对应关系
文件描述符表
在pcb中存在一个指针,指向了一个files_struct结构,这个结构内部包含了一个指针数组。
指针数组的类型是struct file*,这些指针元素指向了被OS管理的文件结构struct file。
这个指针数组被称为文件描述符表,元素的下标就是元素描述符!
因此我们用fd接收的文件打开的返回值,就是这个数组的下标。因此在写入的时候需要传入数组的下标,这样就能找到对应的文件。
发现这个打开的log.txt的文件描述符是
当我们多打开几个文件时
按照数组的下标顺序排列。
0 1 2去哪里了呢?
前面已经说过了,进程启动的时候,会默认打开三个文件
我们向1号文件描述符对应的文件进行输出时,确实在显示器直接打印了输出信息。
从0号文件输入
读取count的大小字节的文件,读取到buf中。
从键盘文件中读取
发现进程进入阻塞状态(S+)
打开显示器、键盘文件不只是C的特性,而是OS的特性!进程会默认打开键盘、显示器、显示器,用来执行IO。
FILE* 和 fd什么关系呢?
FILE---C语言的一个结构体
stdin就是一个FILE*结构体
可以发现stdin stdout stderr确实文件描述符为 0 1 2
stdout与stderr的区别
将1文件(stdout:显示器)关闭之后,发现printf无法打印信息。这就说明了printf内部一定使用了1号文件stdout。
stdout关闭之后,仍然可以将数据输出到stderr(也是显示器文件)
结果:
为什么不是-1呢?这是因为printf认为已经向显示器中写入成功了。
这是因为stderr对应的文件描述符是2号,把1号关了,不管2的!
因此stdout与stderr是有区别的。
文件关闭机制
文件的关闭OS通过管理文件描述符表和struct file来实现的。在struct file中,还存在着引用计数器count。
多个进程可以同时打开一个文件。
因此文件关闭时,只需要让count--,将文件描述符表对应的指针置空即可。
如果count != 0,那么将继续执行功能,如果count == 0,那么将回收这个struct file。
因此,关闭1号文件描述符的文件,只是让count--,1号指针置空。
但是stderr的存在,显示器文件仍然没有被回收!
虽然stderr与stdout指向相同的struct file(OS的文件管理对象),但是stderr与stdout不相互干扰的原因:把1关闭之后,只需要让count--即可,但是不影响stderr的执行。
标签:文件,写入,基础,描述符,stderr,linux,打开,OS From: https://blog.csdn.net/2302_80190394/article/details/143268114