医疗器械注册证,青岛百度排名优化,手机网站分享代码,seo推广公司哪家好学习之前#xff0c;首先要认识什么是文件#xff1f;
空文件也是要在内存中占据空间的#xff0c;因为它还有属性数据。文件 属性 内容文件操作 对内容 对属性 或者对内容和属性的操作标定一个文件的时候#xff0c;必须使用#xff1a;路径文件名#xff0c;文件具…学习之前首先要认识什么是文件
空文件也是要在内存中占据空间的因为它还有属性数据。文件 属性 内容文件操作 对内容 对属性 或者对内容和属性的操作标定一个文件的时候必须使用路径文件名文件具有唯一性如果没有指明文件路径默认是对当前路径的文件进行访问文件没有被打开的时候是不能进行访问的二进制可执行文件在没有运行的时候所谓的文件操作都没有执行磁盘上文件被分为被打开的文件和没有被打开的文件
总结文件操作的本质是进程和被打开文件之间的关系。
一、文件操作
1.1 使用C接口进行文件操作用C语言头文件和C语言在Liunx下的表达形式 在将我们的程序编译完成以后再运行发现生成了一个新的文件并且文件中的内容和我们代码中写的一样。 这个过程中使用的是C语言的接口进行文件操作。以写的方式打开文件名问log.txt的文件没有的这个文件的话就会创建。使用C接口向该文件中写入内容。 不同的编程语言都有文件操作的接口包括CJavaPythonphp等等语言并且它们的操作接口函数都不一样但是它们所在的系统都是Linux系统。
无论上层语言如何变化但是进行文件操作的时候各种语言最终都会调用Linux的文件操作的系统调用接口。
1.2 文件操作的系统调用
open函数 可以看到函数声明有两个一个是两个参数的一个是三个参数的它们必然不是函数重载因为Linux是用纯C实现的。 const char* pathname这是文件路径也就是我们要打开的文件所在的路径其中包括文件名如果没有路径只有文件名的话默认在当前路径打开。int flags打开方式选项标志位。在使用C语言进行文件操作的时候打开方式有“w”“r”“a”等方式系统调用open也有只是将这些标志放在了一个32位的变量中。mode_t mode它是权限值如果这个文件不存在那么以写的方式打开的时候就会创建这个文件在创建文件的时候需要给这个文件设定权限(使用八进制数)。如果这个文件存在的话那么就不用传第三个参数了因为文件的权限已经确定了。返回值是一个int类型的参数具体的在后面本喵会介绍但是如果打开失败就会返回-1。 执行我们写的代码后log.txt文件是创建了但是它是红色的说明它有错误。可以看到它前面的权限是乱的因为我们没有指定创建文件时的权限。 但是权限并不是我们设定的0666而是0664这是因为有默认权限掩码(umask)的影响。 此外还有close函数write函数使用 man 函数名指令查看相应参数
二、文件描述符fd
在使用系统调用open时返回的那个整数就是文件描述符。 将文件名使用宏的方式打开多个文件。 现在我们见到了文件描述符发现它就是几个数字。
当一个文件被打开后操作系统会创建一个对应的结构体对象类型是struct file。
struct file
{//文件大小//文件类型......//文件的各种属性
}每打开一个文件操作系统就会创建这样的一个结构体对象将被打开的文件描述出来。将多个这样的结构体对象采用一定的方式组织起来比如链表的方式以方便操作系统管理这些被打开的文件。 在描述进程的结构体task_struct中有一个指针struct files_struct* files这个指针指向一个结构体对象该对象类型如下
struct files_struct
{//......struct file* array[];
}struct files_struct结构体中存在一个指针数组array该数组中的指针指向的是一个个struct file类型的结构体对象。换言之该数组中放的是被打开文件结构体对象的地址。每一个被指向的struct file结构体对象都描述着一个被打开的文件。 在前面我们看到打印出来的fd值是连续的小整数这些小整数就是struct files_struct 结构体中指针数组struct file* array[]的下标。
文件描述符的本质就是数组的下标。 当一个程序被加载到内存中操作系统会创建一个结构体struct task_struct对象在该结构体中有一个指针struct files_struct* files指向一个struct files_struct结构体对象。这个结构体也被叫做进程描述符表该结构体中有一个数组struct file* array[]数组中存放的是被打开文件的结构体对象的地址。如上图中下标为3也就是fd的是3的时候访问到的是struct file* array[3]。通过数组中访问到的地址可以找到对应打开文件的结构体对象如上图中的struct file log.txt。 只有被打开的文件才会在内存中创建struct file结构体对象没有被打开的文件就静静的躺在磁盘上。
不是该进程打开的文件该进程执行的文件描述符表中也没有这个文件的地址。
2.1 文件描述符fd0/1/2
在上面打开多个文件的时候我们将打开文件的fd值打印出来发现它是从3开始的。 那么fd 0/1/2是什么呢
C默认会打开三个输入输出流分别是stdinstdoutstderr。 可以看到这三个流是FILE*类型的指针暂时不用管FILE是什么只需要知道它是一个结构体。 使用C语言的文件操作结构打开一个文件再使用系统调用去向文件中写内容。
我们此时已经确定的知道了FILE结构体中是有文件描述符的。 文件描述符0 1 2出现了。 fd 0标准输入流(stdin)fd 1标准输出流(stdout)fd 2标准错误(stderr) 此时我们便清楚了为什么我们打开的文件文件描述符是从3开始的因为012被默认打开的三个流占据了。 2.2 文件描述符的分配规则
为什么我们打开的文件fd是从3开始的不是从5或者6开始的呢 我们将fd0的标准输入流关闭掉再打开文件并且打印fd值。 我们发现此时的fd成了0而不是3了。 同样的将fd2的流关闭在打开文件。 根据这个现象可以得出结论文件描述符fd的分别规则是从小到大按顺序查找将没有被占用的数组下标作为被打开文件的文件描述符fd值。
三、重定向
3.1 输出重定向
前面我们只关闭过0和2没有关闭过1现在我们关闭一下1来看看。 将标准输出关闭然后打开文件并且打印出打开文件的文件描述符fd。 因为将标准输出关闭了所以无法显示。 根据前面分析的文件描述符分配规则可以推断出将标准输出关闭以后再打开一个文件此时这个文件的文件描述符fd等于1。 在将fd1关闭后再打开一个文件从小到大按顺序查找发现数组下标为1的位置没有被占用所以新打开文件的fd就等于1。printf函数原本是要输出到标准输出的也就是fd为1的数组中指向的struct file对象的地址。此时下标为1的数组中不再是标准输出了而变成了我们新打开文件的地址。但是printf已经写死了它仍然会写入到fd为1的文件中所以原本打印在显示器上的内容此时会写入到新打开的文件中。 3.2 输入重定向
使用只读方式打开文件log.txt该文件原本就存在。 将原本struct file* array[]数组中下标0的内容改成下标为fd的内容也就是dup2(fd,0)的作用。使用标准输入函数fgets从标准输入流也就是键盘中读取字符串。屏幕上打印读取到的内容。 运行时直接输出log.txt中的内容没有从键盘获取数据。也就是说fgets函数是从文件中获取到内容而不是标准输入。
这种从标准输入到文件的重定向叫做输入重定向。
3.3 进程独立性
子进程重定向了以后会影响父进程吗根据进程独立性我们可以知道肯定是不会影响到。 在子进程中进行输出重定向父进程同样在标准输出打印。 有两个进程一个父进程一个子进程操作系统维护着两个task_struct结构体如上图红色框所示。每个进程的PCB中都有一个struct files_struct*的指针files。它们各自指向的struct files_struct结构体中都有一个文件描述符表。两个文件描述符表中的内容在子进程刚创建时是一样的所以它们都指向相同的被打开的文件。当子进程将自己文件描述符表中下标为1的文件关闭以后并不影响父进程文件描述符表中下标为1的数组中的内容。 每个进程都会维护自己的文件描述符表所以多个进程就会存在多个文件描述符表但是这些表中的指针指向的被打开文件只有一套。
某个进程进行文件的打开与关闭操作时只需要修改自己的文件描述符表就可以不会对其他进程造成任何影响。
一切皆文件是指在操作系统中一切都是结构体。