【Linux】文件管理
文章目录
- 文件的定义
- 文件管理中的系统级接口
- open
- 其他接口
- 总结
文件的定义
在Linux系统中,文件是操作系统中最基本的数据组织单位之一,几乎所有的资源和操作都被抽象为文件。
简单来说文件我们可以定义为:文件=内容+属性
文件在没有被打开之前都是存储在磁盘上的,只有在打开之后才被加载到内存当中。
为什么文件必须被加载到内存当中?
因为我们在执行文件操作的时候,是需要CPU去执行的,但是CPU是无法直接和磁盘进行交互的,所以需要先把文件加载到内存当中,然后再进行操作
文件是谁在访问?
因为用户启动的所有进程都是shell的子进程,所以可以认为文件是被进程在访问。
我们可以用一个进程来访问一个文件:
先写一段简单的代码:
#include<stdio.h>
int main()
{
FILE* fp = fopen("log.txt","w");
if(fp == NULL)
{
//打开失败
perror("fopen");
return 1;
}
const char *message = "hello file\n";
fputs(message,fp);
fclose(fp);
return 0;
}
代码写完之后,我们创建一个可执行程序。
可执行程序出来之后,我们访问了文件吗?很显然是没有访问的,文件还没有被加载到内存当中,只有当可执行程序运行的时候文件才被加载到了内存当中。
可执行程序执行,一直执行到fopen这句代码的时候,文件才被访问,一直到fcose这行代码,文件才被关闭,整个访问流程最后才结束,在打开文件到关闭文件这个过程当中,我们可以读取文件,或者对文件进行写入。
但是我们用w方式打开文件的时候,每次进入文件都会对以前的内容做覆盖,如果想要在原本的文件内容上做追加可以把打开文件的方式改为a,就可以对文件进行追加。
fopen和fclose诸如此类的接口都是C语言封装的接口,我们来了解一下Linux中的系统级接口。
文件管理中的系统级接口
open
open就是一个系统级接口,第一个参数和fopen是一样的,都是文件名,open的第二个参数是标记位,我们来重点说一下第二个参数:
上面这些就是对应的标记位,这些标记位代表打开的方式
从上到下从左到右依次是:只读,只写,读写,是否创建,文件存在打开之前是否清空文件。
这些标记位的本质其实是用位图实现的,这个位图中只有一个1,但是每个标记位的1的位置不同,通过宏定义来实现标记位。
我们写一段简单的代码来理解这个标记位
#include<stdio.h>
#define ONE (1<<0)
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
void print(int i)
{
if(i & ONE)
{
printf("ONE\n");
}
if(i & TWO)
{
printf("TWO\n");
}
if(i & THREE)
{
printf("THREE\n");
}
if(i & FOUR)
{
printf("FOUR");
}
}
int main()
{
print(ONE | TWO);
return 0;
}
上面这个代码其实就可以通过宏定义一个函数实现多个功能:
可以看见在屏幕上打印了ONE和TWO,其实标记位也是类似的。
接下来用一下open这个接口,先不用管这个返回值。
我们先只打开文件不进行任何操作。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
open("log.txt",O_WRONLY | O_CREAT | O_TRUNC);
return 0;
}
可以看见创建出来的文件是乱码
这是因为,我们没有初始化权限,这下就要介绍第三个参数了,就是mode,mode这个参数是初始化权限。
我们把权限初始化为666,也就是都可读可写。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
return 0;
}
可以发现没有乱码的情况了,但是问题还是出现了,原本我们设计的初始化权限是666,但是创建出来的文件为什么是664呢?
原因:实际权限会受到 umask 的影响。umask 是一个用来设置默认权限的掩码,它会从创建文件时指定的权限中减去相应的位。
我们可以通过设置umask来调整初始化的权限
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
umask(0);
open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
return 0;
}
设置完umask的文件权限:
可以看见设置完umask之后就会变成666的权限。
open的返回值:
open的返回值其实是文件描述符,如果正常打开返回对应的大于等于0的文件描述符,如果打开文件失败会返回-1。
接下来我们来讲讲文件操作的其他几口,结合其他接口谈文件描述符
其他接口
这几个分别代码的是关闭文件,写入文件和读取文件,这三个函数的第一个参数就是文件描述符,通过open返回的文件描述符来向对应的文件写入或者读取文件,或者关闭文件。
所以什么是文件描述符呢?
首先我们知道我们打开一个进程之后这个进程都是会默认打开三个文件的,这三个文件在C语言中是Cstdin,stdout,sdterr,分别代表标准输入流,标准输出流和标准错误流。
这三个文件也有文件描述符,我们来查看一下这三个文件描述符:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
printf("stdin:%d\n",stdin->_fileno);
printf("stdout:%d\n",stdout->_fileno);
printf("stderr:%d\n",stderr->_fileno);
return 0;
}
可以看见这三个文件的文件描述符分别是012,我们现在已经知道close,还有read,还有read都是通过文件描述符来操作的。
我们先来试试,看看可不可以对标准输出和标准输入操作。
首先我们先向标准输出流输出一段字符,也就是屏幕:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
int main()
{
const char *message = "hello world\n";
write(1,message,strlen(message));
return 0;
}
可以看见1确实是标准输出流,我们对标准输出流这个文件写入确实是可以写入的。
其他的就不做演示了。
我们通过打印其文件描述符可以看到是从0开始的,最容易想到的从0开始的东西,就是我们常用的数组了,数组就是从0开始的。
实则不然,文件描述符就是数组的下标。
总结
在 Linux 系统中,文件管理是操作系统的一项核心功能。理解文件的基本概念、文件类型、权限控制以及文件系统的工作原理,对于高效管理和操作文件至关重要。通过掌握如 open、read、write 等系统调用,用户不仅能够进行基本的文件操作,还能通过进程间的文件共享、文件描述符的管理等方式实现更加灵活和高效的文件处理。
此外,文件权限和文件系统的优化同样重要,合理设置文件权限以及理解文件系统的结构,将有助于提高系统的安全性和性能。Linux 提供了强大的工具和命令,帮助用户更好地管理文件,不论是通过命令行操作,还是通过程序进行自动化文件管理,都能为用户带来更便捷的体验。
总的来说,掌握 Linux 文件管理的基本技能,是使用和管理 Linux 系统的基础,也是深入理解系统运行机制的重要一步。