一、文件描述符
1.1 文件描述符本质
- 文件描述符的本质是一个数字,这个数字是进程表中文件描述符表的一个表项,进程通过文件描述符作为index去索引查表得到文件表指针,再间接访问得到这个文件对应的文件表。
- 文件描述符这个数字是open系统调用内部由操作系统遵照一定的规律,自动分配的
- 操作系统规定,fd从0开始依次增加。fd也是有最大限制的。linux中文件描述符表是个数组(不是链表),fd是index,文件表指针是value
1.1 linux中文件描述符的分配
- 调用open时,内核会从文件描述符表中挑选一个最小的未被使用的数字返回。如果之前fd已经占满了0-9,那么我们下次open得到的一定是10.
- linux fd中0、1、2已经默认被系统占用了,因此用户进程得到的最小的fd就是3
- 当我们运行一个程序,得到一个进程,内部就默认已经打开了3个文件,这三个文件对应的fd就是0、1、2。
- 这三个文件分别叫stdin、stdout、stderr。也就是标准输入、标准输出、标准错误。
1.2 标准输入、标准输出
- 标准输入一般对应的是键盘(可以理解为:0这个fd对应的是键盘的设备文件)
- 标准输出一般是LCD显示器(可以理解为:1对应LCD的设备文件)
二、lseek
2.1 文件指针
- 在动态文件中,通过文件指针来表征正在操作的位置。
- 文件指针,就是文件管理表结构体里面的一个指针。
- 文件指针是vnode中的一个元素,这个指针表示当前正在操作文件流的哪个位置。
- 这个指针不能被直接访问,linux系统用lseek函数来访问这个文件指针。
2.2 lseek函数
lseek函数是一个API ,在linux中 用 命令 man 2查询
man 2 lseek
2.3 lseek测文件长度
int cal_len(const char *pathname)
{
// fd 就是file descriptor,文件描述符
int fd = -1;
int ret = -1;
// 第一步:打开文件
fd = open(pathname, O_RDONLY);
if (-1 == fd)// 有时候也写成: (fd < 0)
{
perror("文件打开错误");
return -1;
}
// 此时文件指针指向文件开头
// 用lseek将文件指针移动到末尾,然后返回值就是文件指针距离文件开头的偏移量,也就是文件的长度了
ret = lseek(fd, 0, SEEK_END);
return ret;
}
三、dup
3.1 dup进行描述符复制
- dup系统调用对fd进行复制,会返回一个新的文件描述符(譬如原来的fd是3,返回的就是4)
- dup系统调用不能指定复制后得到的fd的数字是多少,由操作系统内部遵守fd的分配原则自动分配
3.2 dup的缺陷
- dup不能指定分配新文件描述符的数字
3.3 dup对输出的重定位
0、1、2这三个fd被标准输入、输出、错误通道占用,用close(1)关闭标准输出,使用dup重新分配得到1这个fd,就把oldfd打开的这个文件和1这个标准输出通道给绑定起来了。这就叫标准输出的重定位
#define FILENAME "1.txt"
int main(void)
{
int fd1 = -1, fd2 = -1;
fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd1 < 0)
{
perror("open");
return -1;
}
printf("fd1 = %d.\n", fd1);
close(1); // 1就是标准输出stdout
// 复制文件描述符
// fd2一定等于1,因为前面刚刚关闭了1,这句话就把
// 1.txt文件和标准输出就绑定起来了,所以以后输出到标准输出的信息就可以到1.txt中查看了。
fd2 = dup(fd1);
printf("fd2 = %d.\n", fd2);
printf("this is for test");
close(fd1);
return -1;
}
四、文件属性
4.1 文件的权限列表
在linux中 ls -l 打印出来的权限一共9位,3个一组
- 第1组3个表示文件的属主(owner、user)对该文件的可读、可写、可执行权限
- 第2组3个表示文件的属主所在的组(group)对该文件的可读、可写、可执行权限
- 第3组3个表示其他用户(others)对该文件的可读、可写、可执行权限
4.2 access函数检查权限设置
- 在操作文件之前先判断当前是否有权限做这个操作,如果有再做,如果没有则提供错误信息给用户。
- access函数可以测得,当前执行程序的用户在当前环境下,对目标文件是否具有某种操作权限。
- access函数失败返回-1
#define NAME "1.txt"
int main(void)
{
int ret = -1;
ret = access(NAME, F_OK);//判断是否可以打开
ret = access(NAME, R_OK);//判断是否可读
ret = access(NAME, W_OK);//判断是否可写
ret = access(NAME, X_OK);//判断是否可执行
return 0;
}
4.3 用命令修改权限
- chmod是一个linux命令,用来修改文件的各种权限属性
- chmod命令只有root用户才有权利去执行修改
- chmod命令其实内部是用linux的一个叫chmod的API实现的
#define NAME "1.txt"
int main(void)
{
int ret = -1;
ret = chmod(NAME, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWOTH);
return 0;
}
4.4 用命令修改属主
- chown命令来修改文件属主
- chown命令是用chown API实现的
4.5 文件权限掩码
- 文件掩码是linux系统中维护的一个全局设置
- umask的作用是用来设定我们系统中新创建的文件的默认权限的
- umask命令就是用umask API实现的