1、通过文件描述符相关的文件的状态信息
fstat
stat:取得文件状态
表头文件
#include<sys/stat.h>
#include<unistd.h>
定义函数
int stat(const char * file_name,struct stat *buf);
lstat
stat和lstat返回的是通过文件名查到的状态信息。它们的结果基本一致,但当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息
实际经常判断的文件的类型
S_ISLNK(st_mode):是否是一个连接
S_ISREG(st_mode):是否是一个常规文件
S_ISDIR(st_mode):是否是一个目录
S_ISCHR(st_mode):是否是一个字符设备.
S_ISBLK(st_mode):是否是一个块设备
S_ISFIFO(st_mode):是否 是一个FIFO文件.
S_ISSOCK(st_mode):是否是一个SOCKET文件
案例1:
观察文件权限
ll text.txt
S_ISDIR:判断目录
S_IRWXU:用户有RWX权限
#include<stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
struct stat statbuf;
mode_t modes;
//stat(“testdir”,&statbuf);
stat("test.txt", &statbuf);
modes = statbuf.st_mode;
//S_IRWXU代表用户可以读,写,执行,S_IXUSR代表用户可以执行
//如果是目录,并且仅仅有用户的执行权限
//S_ISDIR()函数,功能是判断是否为目录
//if(!S_ISDIR(modes) && (modes & S_IRWXU) == S_IXUSR)
if (!S_ISDIR(modes) && (modes & S_IRWXU) == S_IXUSR)
{
printf("ok!\n");
}
else
{
printf("no!\n");
}
return 0;
}
2、空洞文件
lseek() 系统调用可以改变文件的偏移量,但如果程序调用使得文件偏移量跨越了文件结尾,
然后再执行 I/O 操作,将会发生什么情况? read() 调用会返回 0, 表示文件结尾。
write() 调用可以在文件尾后的任意位置写入数据。
在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。
从原来的文件结尾到新写入数据间的这段空间被称为文件空洞。
文件空洞不占用任何磁盘空间,直到某个时点,在文件空洞中写入了数据,
文件系统才会为之分配磁盘块。
空洞的存在意味着一个文件名义上的大小可能比其占用的磁盘存储总量要大(有时大出很多)。
向文件空洞中写入字节,内核需要为其分配存储单元,即使文件大小不变,
系统的可用磁盘空间也将减少。
创建一个无空洞的文件
dd if=/dev/urandom of=testfile1 bs=4096 seek=0 count=1
查看文件大小
ls -lh testfile1
查看文件所占磁盘块大小
du -h testfile1
创建空洞文件
dd if=/dev/urandom of=testfile2 bs=4096 seek=999 count=1
注意:
seek=0,代表文件中写入1块数据(count=1),也就是不多写数据
seek=999,代表文件中多写入了999块数据(一块数据是bs=4096)
查看空洞文件
od -c testfile2
结论:
- 无空洞的文件,文件大小和占用磁盘的大小是一样的。
- 有空洞的文件,文件大小是4M,而占用块大小是 4K。(实际大小根据测试文件定)
实际中的空洞文件的应用场景有两个:
- 下载电源的时候,发现刚刚开始试下载,文件的大小就以及有几百M。
- 创建虚拟机的磁盘镜像的时候,你创建了一个100G的磁盘镜像,但是其实装起系统之后,开始也不过只占用了3,4G的磁盘空间,如果一开始就把100G分配出去,资源是很大的浪费。
/文件lseekhole.c,
使用lseek函数构建空洞文件/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd = -1, i;
ssize_t size = -1;
off_t offset = -1;
/存放数据的缓冲区/
char buf1[] = “01234567”;
char buf2[] = “ABCDEFGH”;
/文件名/
char filename[] = “hole.txt”;
int len = 8;
/*创建文件hole.txt*/
fd = open(filename, O_RDWR | O_CREAT, S_IRWXU);
if (-1 == fd){
/*创建文件失败*/
return -1;
}
/*将buf1中的数据写入到文件Hole.txt中*/
size = write(fd, buf1, len);
if (size != len){
/*写入数据失败*/
return -1;
}
/*设置文件偏移量为绝对值的32*/
offset = lseek(fd, 32, SEEK_SET);
if (-1 == offset){
/*设置失败*/
return -1;
}
/*将buf2中的数据写入到文件hole.txt中*/
size = write(fd, buf2, len);
if (size != len){
/*写入数据失败*/
return -1;
}
/*关闭文件*/
close(fd);
return 0;
}
3、特殊的文件
/dev/null : 在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。任何写入它的输出都会被抛弃。
#将查找结果的输出重定向到空设备
find ./ -name “*.c” 1>/dev/null
/dev/zero : 在类UNIX 操作系统中, /dev/zero 是一个特殊的文件,当你读它的时候,它会提供无限的空字符(NULL, ASCII NUL, 0x00)。
/dev/zero,是一个输入设备,你可你用它来初始化文件。
/dev/zero------该设备无穷尽地提供0,可以使用任何你需要的数目——设备提供的要多的多。它可以用于向设备或文件写入字符串0
4、dup和dup2
dup和dup2
1.概述
dup和dup2也是两个非常有用的调用,它们的作用都是用来复制一个文件的描述符。
它们经常用来重定向进程的stdin、stdout和stderr。
2.头文件
#include <unistd.h>
3.函数接口
int dup(int fd);
源描述符fd,返回值是描述符表中最小的没有被使用的文件描述符。
返回的描述符和源描述符fd指向同一个文件
int dup2(int fd, int fd2);
dup2函数成功返回时,目标描述符fd2,将变成源描述符fd的复制品,
换句话说,两个文件描述符现在都指向同一个文件,即函数第一个参数fd指向的文件。
使用dup和dup2重定向和还原
5、fcntl函数(只做了解)
用于获得和改变已经打开文件的性质
6、mmap
了解mmap的原理
/把文件映射成虚拟内存地址/
void *mmap(void *addr, //从进程的那个地址开始映射,如果为NULL,由系统指定;
size_t length, //映射的地址空间的大小
int prot, //内存的保护模式
int flags,//映射模式 有匿名,私有,保护等标记 具体查询man手册;
int fd, //如果为文件映射,则此处为文件的描述符号
off_t offset);//如果为文件映射,则此处代表定位到文件的那个位置,然后开始向后映射。
返回值:映射成功,返回首地址;
mmap:效率高
原理是:mmap的执行,仅仅是在内核中建立了文件与虚拟内存空间的对应关系。用户访问这些虚拟内存空间时,页面表里面是没有这些空间的表项的。当用户程序试图访问这些映射的空间时,于是产生缺页异常。内核捕捉这些异常,逐渐将文件载入。所谓的载入过程,具体的操作就是read和write在管理pagecache。
可以看出使用mmap后发现,系统调用所消耗的时间远远比普通的read少很多。
7、lsof
了解
查看某个文件被哪些进程在读写
lsof是什么意思
list open files
查看某个文件被哪些进程在读写
lsof 文件名
查看某个进程打开了哪些文件
lsof –c 进程名
lsof –p 进程号
lsof用法小全
lsof abc.txt 显示开启文件abc.txt的进程
lsof -i :22 知道22端口现在运行什么程序
lsof -c nsd 显示nsd进程现在打开的文件
lsof -g gid 显示归属gid的进程情况
lsof +d /usr/local/ 显示目录下被进程开启的文件
lsof +D /usr/local/ 同上,但是会搜索目录下的目录,时间较长
lsof -d 4 显示使用fd为4的进程
lsof -i [i] 用以显示符合条件的进程情况
现在1000个socket连接
read
write
socket也是文件的一种,描述符
select