目录
文件描述符
PCB进程控制块:本质是结构体
成员:文件描述符表
文件描述符:0-1023 表中可用的最小的
0-STDIN_FILENO
1-STDOUT_FILENO
2-STDERR_FILENO
阻塞、非阻塞:是设备、网络文件的属性
产生阻塞的场景:读设备文件、读网络文件。(读常规文件无阻塞概念)
Fcntl函数
fcntl函数类似一个杂货铺,本文主要描述使用fcntl来改变文件属性
Fcntl函数
int flags = fcntl(fd, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
获取文件状态:F_GETFL
设置文件状态:F_SETFL
e.g.
int main(void)
{
char buf[10];
int flags, n;
flags = fcntl(STDIN_FILENO, F_GETFL);
if(flags == -1) {
perror("fcntl error");
exit(1);
}
flags |= O_NONBLOCK;
int ret = fcntl(STDIN_FILENO, F_SETFL, flags);
if(ret == -1) {
perror("fcntl error");
exit(1);
}
}
lseek函数
off_t lseek(int fd, off_t offset, int whence)
参数:
fd:文件描述符
offset:偏移量
whence:起始偏移量 SEEK_SET/SEEK_CUR/SEEK_END
返回值:
成功:较起始位置偏移量
失败:-1, errno
读和写使用一个偏移量
e.g.
int main()
{
int fd, n;
char msg[] = "it is a test for lseeek\n";
char ch;
fd = open("lseek.txt", O_RDWR | O_CREAT, 0644);
if(n < 0) {
perror("open error");
exit(1);
}
write(fd, msg, strlen(msg));
lseek(fd, 0, SEEK_SET); //读和写光标使用同一个位置,如果将此句注释掉,结果会读出0数据
//因为write函数写完之后,光标在文件的末尾
while((n = read(fd, &ch, 1))) {
if(n < 0) {
perror("read error");
exit(1);
}
}
write(STDOUT_FILENOM, &ch, n);
close(fd);
}
应用场景:
1、文件的读和写使用同一偏移量
2、使用lseek去获取文件大小。
int i = off_t lseek(fd, 0, SEEK_END);
3、使用lseek去拓展文件大小、要想使文件大小真正拓展,必须引起IO操作
可以使用truncate函数,直接拓展文件
int ret = truncate("lseek.txt", 200);
常见参数:
传入参数:
1:指针作为函数参数
2:通常由const关键字修饰
3:指针指向有效区域,在函数内部做读操作
传出参数:
1:指针作为函数参数
2:在函数调用之前,指针指向的空间可以无意义,但必须有效
3:在函数内部,写操作
4:函数调用结束后,充当返回值
传入传出参数:
1:指针作为函数参数
2:在函数调用之前,指针指向的空间有实际意义
3:在函数内部,先做读操作,再做写操作
4:函数调用结束后,充当返回值
文件存储
inode:其本质为结构体,存储文件的属性信息。如:权限、类型、大小、时间、用户、盘块位置...也叫作文件属性管理结构,大多数的inode都存储在磁盘上
dentry:目录项,其本质也是结构体,重要成员变量有两个:文件名、inode;而文件内容保存在磁盘盘块上
stat函数
获取文件属性,从inode结构体中获取
int stat(const char *path, struct stat*buf);
参数:
path:文件路径
buf:(传出参数)存放文件属性
返回值:
成功:0
失败:-1, errno
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
e.g.
int main(int argc, char *argv[])
{
struct stat, sbuf;
int ret = stat(argv[1], &sbuf);
if(ret == -1) {
perror("stat error");
exit(1);
}
int reg = S_ISREG(sbuf.st_mode);
printf("reg = %d\n", reg);
return 0;
}
stat和lstat函数区别:
stat会穿透符号链接
lstat不会穿透符号链接
link/unlink函数
隐式回收:当进程结束运行时,所有该进程打开的文件会被关闭,申请的内存空间会被释放,系统的这一特性称之为隐式回收系统资源
我们删除文件时,从某种意义上讲,只是让文件具备了被释放的条件,清除文件时,如果文件的硬链接数到0了,没有dentry对应,但该文件不会马上被释放,要等到所有打开该文件的进程关闭该文件,系统才会调时间将该文件释放掉