一切皆文件
Linux的核心思想就是“一切皆文件”
Linux 中所有内容都是以文件的形式保存和管理的,即一切皆文件,普通文件是文件,目录(Windows 下称为文件夹)是文件,硬件设备(键盘、监视器、硬盘、打印机)是文件,就连套接字(socket)、网络通信等资源也都是文件。
——引用自C语言中文网
I/O设备也被模型化为文件,对于输入输出的操作就变成了对于文件的读和写,Linux内核提供接口给用户
文件类型
-
普通文件:包含任意数据
-
目录:包含一组链接的数据
命令:mkdir创建一个目录
ls查看目录内容
rmdir删除目录 -
套接字:用来与另一个进程进行跨网络通信的文件
-
命名通道
-
符号链接
-
字符与块设备
硬链接与软连接的区别
在linux中,文件分为两个部分
- 文件数据块(记录文件真实内容的地方)
- 元数据(记录文件的属性)
其中元数据包含了inode结点,inode结点记录文件的数据区块号码,想要读取文件时,需要通过文件名指向正确的inode号码,通过inode指向文件数据区块,所以inode是文件的唯一标识。
软链接类似于windows中的快捷方式,软链接有自己的inode结点,结点指向的数据区块里面存储的是另以文件的路径名指向
特点:
- 软链接有自己的文件属性和权限
- 类似快捷方式,若删除软链接,对原有文件不产生影响
- 可以对文件,目录进行链接
- 可以跨文件系统
- 有自己的inode号
- 可以对不存在的文件进行软链接
硬链接则是将不同文件名的文件指向同一个inode结点
特点:
- 不可以对目录链接
- 只可以对已经存在的文件进行链接
- 删除硬链接可能会对文件产生影响(若最后一个指向inode结点的文件被删除,那么文件就会被删除)
- 硬链接有相同的inode号
- 不可以跨文件系统
linux的文件系统:
将存储空间分为了三个区块:
- 超级区块:记录文件系统的整体信息
- inode:记录文件属性
- 数据区块:记录文件的实际内容
其中inode与数据区块都有编号,inode占整个文件系统空间的10%,所以当inode空间不足时,也不能创建文件,所以定期清理内存是必要的。
打开文件
调用open函数来创建或者打开一个文件
int open(char *filename, int flags, mode_t mode);
//若成功返回文件描述符,若失败返回-1
每一个进程都有一张文件描述符表,默认打开三个文件
0 | 标准输入(stdin) |
---|---|
1 | 标准输出(stdout) |
2 | 标准出错(stderr) |
这三个文件描述符被占用了,所以在初始状态下打开文件,描述符从3开始
其中flags为以何种方式打开此文件
O_RDONLY:可读
O_WRONLY:可写
O_RDWR:可读可写
O_CREAT:若文件不存在,就创建一个新的文件
O_TRUNC:如果文件已经存在,则截断
O_APPEND:每次写操作时,设置文件至文件的末尾
mode为访问权限位
掩码 | 描述 |
---|---|
S_IRUSR | 拥有者可以读这个文件 |
S_IWUSR | 拥有者可以写这个文件 |
S_IEUSR | 拥有者可以执行这个文件 |
S_IRGRP | 拥有者所在组的成员可以读这个文件 |
S_IWGRP | 拥有者所在组的成员可以写这个文件 |
S_IEGRP | 拥有者所在组的成员可以执行这个文件 |
S_IROTH | 任何人可以读这个文件 |
S_IWOTH | 任何人可以写这个文件 |
S_IEOTH | 任何人可以执行这个文件 |
在使用的时候可以使用这些宏,也可以使用数字,这是一个7进制的数,按照上文表的顺序,每三个宏,决定一个数字
例如:
0111表示S_IEUSR|S_IEGRP|S_IEOTH
关闭文件
使用close函数关闭文件
int close(int fd);
//若成功关闭就返回0,若关闭失败返回-1
读文件
#include<unistd.h>
ssize_t read(int fd,void *buf,size_t n);
//若成功返回读的字节数,若EOF为0,若出错为-1
n为预计读的字节数
返回值的类型是ssize_t(有符号整型)
读文件就是将内容复制到缓冲区
写文件
#include<unistd.h>
ssize_t write(int fd,const void *buf,size_t n);
//若成功返回写的字节数,出错返回-1
const:常量限制符,告诉编译器此变量不可以被修改
以下代码用于将标准输入设备用户敲击的字符输出到标准输入(显示器)上,Read,Write函数封装了对read,write函数出错的解决
int main(void){
char c;
while(Read(STDIN_FILENO,1)!=0){
Write(STDOUT_FILENO,1);
}
}
共享文件
linux内核用三个数据结构来表示打开的文件
描述符表:每个进程都有,每个打开的米描述符表项都指向文件表中的一个表项
文件表:包括当前的文件位置,引用计数(指向该表项的描述符个数),指向v-node的指针
v-node表:包含stat结构中的大多数信息(stat:文件的元数据)
如果以同一个filename打开文件两次,就会出现以下情况,每个描述符都有自己的文件位置,但是他们指向的文件的内容是一样的
int main(int argc, char *argv[])
{
int fd1, fd2;
char c;
fd1 = Open(fname, O_RDONLY, 0);
fd2 = Open(fname, O_RDONLY, 0);
Read(fd1, &c, 1);
Read(fd2, &c, 1);
printf("c = %c\n", c);
Close(fd1);
Close(fd2);
return 0;
}
由于fd1与fd2指向的是两个不同的文件表项,但文件表项指向的v-node是同一个,所以两次read的结果是一样的,都是文件的第一个字符
I/O重定向
I重定向:输入到终端改变为输入到文件
O重定向:输出到终端变为输出到文件
其中一种重定向的方式就是使用dup2函数
int dup2(int oldfd,int newfd);
重定向的实质就是将文件描述符指向另一个文件
dup2(fd4,fd1);
如下图:
由于两个描述符指向的是同一个文件表项昂,所以对fd1操作,相当于对fd4操作