操作系统:04 文件

目录

1 文件IO

1.1 文件的分类

1.2 文件操作相关的系统调用

1.2.1 头文件

1.2.2 系统调用函数

2 随机读写

3 系统IO读写文本文件

3.1 写文本文件

3.2 读文本文件

3.3 文件描述符

3.3.1 相关函数

3.4 文件同步

3.5 文件属性

3.6 文件权限

3.6.1 权限屏蔽码

3.6.2 修改文件大小

3.7 删除和重命名

3.8 链接文件

3.8.1 软、硬链接文件

 3.8.2 什么是软、硬链接文件

3.8.3 创建链接文件函数

3.10 目录文件操作


1 文件IO

        UNIX/Linux系统把所有的服务、设备都抽象成文件看待,并提供了一套简单而统一的系统接口,这部分系统接口就是所谓的系统文件读写,简称系统IO

        如果使用的是标准c库中的文件读写函数,简称为标准IO

1.1 文件的分类

        可用ls -l查看 权限前xxx xxx xxx的之前那位就可以判断文件类型

文件类型标志符说明
普通文件-包括纯文本文件、二进制文件、压缩文件等
目录文件d类比于window的文件夹注意必须有x执行权限才能进入目录
块设备文件b用于存储大数据的设备,例如硬盘
字符设备文件c例如键盘、鼠标
管道文件p有名管道为主
链接文件l类似于Windows的快捷方式
Socket文件s通常用于网络设备之间数据的连接交互

1.2 文件操作相关的系统调用

1.2.1 头文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

1.2.2 系统调用函数

int open(const char *pathname, int flags);

功能:打开文件

pathname:文件路径

flags:文件打开方式

O_RDONLY只读O_WRONLY只写O_RDWR读写
O_CREAT文件不存在则创建O_TRUNC文件存在则清空打开O_APPEND追加
O_EXCL文件存在,配合O_CREAT则失败
int open(const char *pathname, int flags, mode_t mode);

功能:创建文件,

flags:必须为O_CREAT,mode参数需要给值

mode:

S_IRWXU00700用户读写执行权限
S_IRUSR00400用户读权限
S_IWUSR00200用户写权限
S_IXUSR00100用户执行权限
S_IRWXG00070组读写权限
S_IRGRP00040组写权限
S_IWGRP00020组读写权限
S_IXGRP00010组执行权限
S_IRWXO00007其他用户读写权限
S_IROTH00004其他用户读权限
S_IWOTH00002其他用户写权限
S_IXOTH00001其他用户执行权限

注意:可以直接使用八进制数表示三组权限,例如:0644 0664 0775

返回值:文件描述符,成功返回一个非负整数,类似FILE*,代表了打开后的文件

int creat(const char *pathname, mode_t mode);

功能:创建文件

mode:同上

ssize_t write(int fd, const void *buf, size_t count);

功能:把内存中的数据写入文件中

fd:文件描述符,open的返回值

buf:待写入内存的首地址

count:要写入的字节数

返回值:成功写入的字节数

ssize_t read(int fd, void *buf, size_t count);

功能:把文件中的内容读取到内存中

fd:文件描述符,open的返回值

buf:待读入的内存的首地址

count:要读取的字节数

返回值:实际读取到的字节数

int close(int fd)

功能:关闭文件

fd:文件描述符,open的返回值

返回值:成功0,失败-1

注意:

        read和write都是fwrite和fread的底层调用,正常情况下:标准IO比系统IO的速度更快

原因:

        标准IO中有缓冲区机制,在写数据时,不是每次都调用系统IO,而是把写入的数据存储在临时的缓冲区中,当缓冲区满时,才会调用一次系统IO写入数据到文件中

        直接使用系统IO时,会频繁切换内核态和用户态,非常耗时

        如果给系统IO人为增加所谓的缓冲区,那么它的速度一定会比标准IO快

2 随机读写

        系统IO下,每个打开的文件都有一个读写的位置指针,记录了从哪个字节开始进行读写文件,并且第文件进行读写操作时,它会自动往后移动,当想要在任意位置进行读写文件时,可以通过改变该位置指针的位置来进行随机读写

标准IO:fessk

系统IO:

off_t lseek(int fd,off_t offset,int whence);

offset:偏移值 字节为单位

whence:基础位置

        SEEK_SET 文件开头

        SEEK_CUR 文件末尾

        SEEK_END 文件末尾

返回值:调整后位置指针所在文件的第几个字节

        注意:当文件位置指针越过末尾后再写入数据时,越过的地方会形成"黑洞",该段"黑洞"会计算入文件大小中,但是不占用磁盘空间

3 系统IO读写文本文件

        没有提供类似于fprintf和fscanf放入函数,因此不能直接读写文本文件

3.1 写文本文件

    数据通过sprintf转换成字符串,然后系统IO写入

3.2 读文本文件

    把数据读出到字符串中,然后sscanf解析转换成对应的数据再使用

3.3 文件描述符

① 非负整数,代表了打开的文件

② 由系统调用完成后返回,要被内核空间使用  

③ 它代表了一个内核对象(类似文件指针),因为内核不能暴露它的地址,因此不能像文件指针返回一个对象地址

④ 内核中有一张表格记录了所有打开的文件对象,使用它们所在位置的下标作为该对象的文件描述符,相当于访问文件的凭证,是当前时间内唯一的

内核中有三个默认打开的文件描述符:

        0   标准输入STDIN_FILENO     stdin (FILE*)  

        1   标准输出STDOUT_FILENO    stdout

        2   标准错误STDERR_FILENO    stderr

3.3.1 相关函数

int dup(int oldfd);

功能:复制一个打开的文件描述符

返回值:返回一个没有使用过的最小的文件描述符,失败返回-1

int dup2(int oldfd, int newfd);

功能:复制一个打开的文件描述符,复制成指定的值

注意:

        ① 如果newfd复制前已经打开,会先关闭,后复制

        ② 如果复制成功,相当于两个值不同的文件描述符对应同一个文件

3.4 文件同步

        在写入数据时,内存与磁盘之间有一块缓冲区,好处是降低了磁盘读写次数,提高了读写的效率

        但是这种机制带来的后果是磁盘中的数据有可能与实际写入的数据不匹配,系统提供了系统函数可以让缓冲区中的数据立即写入到磁盘

void sync(void);

功能:把缓冲区中的数据立即同步到磁盘

注意:并不会等待所有数据同步完成后才返回,而是发出同步指令后立即返回

int fsync(int fd);

功能:把指定文件的内容从缓冲区同步到磁盘

注意:会等待同步结束后才返回

int fdatasync(int fd);

功能:把指定文件的内容从缓冲区同步到磁盘,只同步文件的内容,不会同步文件属性

注意:会等待同步结束后才返回

3.5 文件属性

int stat(const char *pathname, struct stat *buf);

功能:根据文件路径获取文件的属性

buf:存储文件属性的结构体指针,是输出型参数

int fstat(int fd, struct stat *buf);

功能:根据文件描述符获取文件的属性

int lstat(const char *pathname, struct stat *buf);

功能:获取软链接文件的文件属性

struct stat:

dev_t     st_dev设备IDdev_t     st_rdev总字节数
ino_t     st_inoinode节点号off_t     st_sizeIO块字节数
mode_t    st_mode文件的类型和权限blksize_t st_blksize占用512字节的块数
nlink_t   st_nlink硬链接数blkcnt_t  st_blocks最后访问时间
uid_t     st_uid用户IDstruct timespec st_atim最后修改时间
gid_t     st_gid组IDstruct timespec st_mtim属性最后修改时间
struct timespec st_ctim特殊设备ID

st_mode: 

S_IFMT0170000识别文件类型的掩码
S_IFSOCK0140000socket文件
S_IFLNK0120000链接文件
S_IFREG0100000普通文件
S_IFBLK0060000块设备文件
S_IFDIR0040000目录文件
S_IFCHR0020000字符设备文件
S_IFIFO0010000管道文件

注意:可以使用 st_mode&S_IFMT 的结果对比是哪个文件

    另外:还可以使用提供的宏函数识别st_mode是哪个文件

    S_ISREG(st_mode)  is it a regular file?

    S_ISDIR(m)  directory?

    S_ISCHR(m)  character device?

    S_ISBLK(m)  block device?

    S_ISFIFO(m) FIFO?

    S_ISLNK(m)  symbolic link?

    S_ISSOCK(m) socket?

3.6 文件权限

int access(const char *pathname, int mode);

功能;检查当前用户对文件的权限有哪些

pathname:待测试的文件

mode:想要测试的权限

        R_OK    是否有读权限

        W_OK    是否有写权限

        X_OK    是否有执行权限

        F_OK    是否存在该文件

返回值:有该权限返回0 没有返回-1

int chmod(const char *pathname, mode_t mode);

功能:根据路径修改文件权限

mode:由3位八进制数组成的权限码

        0644    普通文件

        0755    可执行文件

int fchmod(int fd, mode_t mode);

功能:根据文件描述符修改文件权限

3.6.1 权限屏蔽码

        如果我们有一些权限不想用户在创建文件的时候具备,可以通过设置权限屏蔽码来屏蔽文件创建是具备某些权限

命令:

        umask 查看当前终端的权限屏蔽码

        umask 0xxx 临时修改当前终端的权限屏蔽码

函数:

mode_t umask(mode_t mask)

功能:修改当前进程权限屏蔽码

mask:新的屏蔽码

返回值:原来的屏蔽码

注意:

        ① 权限屏蔽码不能影响 命令chmod 函数chmod,只会影响创建文件函数open/creat

        ② 修改权限屏蔽码只是临时修改,如果关闭终端后,会还原,想要永久修改需要修改配置文件

3.6.2 修改文件大小

int truncate(const char *path, off_t length);

功能:修改文件大小

length:想要修改后的总字节数

注意:length<原总字节数 从末尾抹除多余内容

int ftruncate(int fd, off_t length);

功能:修改文件大小

3.7 删除和重命名

int remove(const char *pathname);

功能:C标准库提供删除文件函数,底层调用unlink\rmdir

int unlink(const char *pathname);

功能:系统调用函数,删除文件

int rename(const char *oldpath, const char *newpath);

功能:重命名文件

3.8 链接文件

Linux的文件系统主要有两个分区部分:

        inode:128Byte,主要记录文件权限、文件大小、所有者、时间等内容

        block数据块区:默认4k,记录了文件名和文件中真正的数据内容

        每个文件都有一个唯一的inode和若干个block,当要读取文件时,要先借助目录文件的block中记录的目录中文件的文件名和inode号来找到该文件的inode,从而读取到对应的block数据块

3.8.1 软、硬链接文件

        硬链接文件:硬链接文件没有专门创新的独属于自己的inode和block,只是在不同于被链接文件的目录中复制了一份被链接文件的inode,通过该inode也可以访问被链接文件的block。

        软链接文件:软链接文件会建立属于自己的新的inode和block,但是block中存储的是被链接文件的inode号和文件名。

区别:

        ① 删除被链接文件时,只是删除了该文件的inode信息块的内容,而不会删除block,所以源文件删除会影响软链接,软链接会无法找到源文件;源文件删除不影响硬链接,让可以访问到源文件的block

        ② 当硬链接数为0时,系统才认为该文件被删除

        ③ 如果修改硬链接文件的内容,被链接文件也会随之改变

④ 硬链接文件不能链接目录,软链接可以

⑤ 可以跨文件系统创建软链接,对不存在的文件创建软连接

 3.8.2 什么是软、硬链接文件

        硬链接文件:硬链接文件没有专门创新的独属于自己的inode和block,只是在不同于被链接文件的目录中复制了一份被链接文件的inode,通过该inode也可以访问被链接文件的block。

        软链接文件:软链接文件会建立属于自己的新的inode和block,但是block中存储的是被链接文件的inode号和文件名。

区别:

        ① 删除被链接文件时,只是删除了该文件的inode信息块的内容,而不会删除block,所以源文件删除会影响软链接,软链接会无法找到源文件;源文件删除不影响硬链接,让可以访问到源文件的block

        ② 当硬链接数为0时,系统才认为该文件被删除

        ③ 如果修改硬链接文件的内容,被链接文件也会随之改变

        ④ 硬链接文件不能链接目录,软链接可以

        ⑤ 可以跨文件系统创建软链接,对不存在的文件创建软连接

3.8.3 创建链接文件函数

int link(const char *oldpath,const char *newpath);

功能:创建硬链接文件

注意:硬链接文件的类型与被链接文件相同

int symlink(const char *target, const char *linkpath);

功能:创建软链接文件

注意:文件类型为l

3.10 目录文件操作

int mkdir(const char *pathname, mode_t mode);

功能:创建一个空目录

mode:目录的权限,要有执行权限才能进入目录

int rmdir(const char *pathname);

功能:删除空目录

int chdir(const char *path);

功能:在当前进程中更改当前工作路径为path,相当于cd

int fchdir(int fd);

功能:更改当前工作路径为fd目录文件描述符所在目录

char *getcwd(char *buf, size_t size);

功能:获取当前的工作路径,相当于pwd

DIR *opendir(const char *name);

功能:打开一个目录

返回值:该目录的目录流,目录流中记录了该目录中所有文件的信息

DIR *fdopendir(int fd);

功能:通过目录的文件描述符,打开一个目录

返回值:该目录的目录流,目录流中记录了该目录中所有文件的信息

struct dirent *readdir(DIR *dirp);

功能:从目录流中读取一条文件记录

返回值:存储一个文件信息的结构体指针   

struct dirent 

ino_t  d_inoinode号
off_t  d_off下一条记录的偏移量
unsigned short  d_reclen当前记录的长度
unsigned char  d_type文件类型
char  d_name[256]文件名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就酱77叭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值