用户无法直接访问内核区,但很多操作都需要访问内核区才能完成,比如读写磁盘数据、进程/线程操作等。为此,Linux操作系统提供了一系列的系统函数供用户调用以访问内核区,也就是说:系统函数充当了一个“房屋中介”一样的角色:房东老爷不想成天和房客打交道,但又断不能将房子空闲,因为这是对生产资料的严重浪费,于是乎,房东老爷和房屋中介一拍即合,房东老爷委托中介管理房屋,租户(用户)只需和中介(系统函数)打交道租用房东老爷(内核)的房子。于是就形成了一个诡异的局面:房东老爷占据着生产资料,无需付出任何劳动,就能获取不菲的收入;而中介联合物业,可谓是“珠联璧合”,一齐向万千牛马收取这样或那样的费用...而牛马,又能做什么?
1. 文件的打开和关闭
作为广大的劳动人民,做事情向来有始有终,在Linux中的文件IO操作也是一样,打开了一个文件,就一定要记得关闭已打开的文件。因为这能充分利用系统资源,避免有限的资源浪费...
(1)open
函数原型
-
打开一个已经存在的文件:
int open(const char *pathname, int flags); -
打开磁盘文件, 如果文件不存在, 就会自动创建:
int open(const char* pathname, int flags, mode_t mode);
参数介绍
- const char *pathname: 表示打开的文件名
- int flags:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写);可选属性,和前面三种联合使用:O_APPEND(数据追加,不覆盖)、O_CREAT(如果文件不存在则创建文件,存在则无操作)、O_EXCL(和O_CREAT一起使用,如果文件存在,则函数返回-1,表示打开失败)
- mode_t mode:在创建新文件时才需要指定,用于指定权限,这是一个八进制整数,如0777,表示对所属用户、所属组和其他都具有读、写和执行权限
返回值
-
大于0的整数:表示打开成功,并将该整数记录到进程内核区的PCB中的文件描述符表中
-
-1:打开失败
(2)close
#include <unistd.h>
int close(int fd);
文件关闭的函数很简单:fd表示open返回的非负整数;返回值要么为0(表示关闭成功),要么为-1(关闭失败)
2.文件的读写操作
做事情不但有始有终,最重要的是过程,Linux中文件操作开始之后(open函数调用成功之后),我们确实可以什么都不做,然后将其关闭,但这样做的意义就有些抽象了,常见的文件操作是读写数据,即向将数据从磁盘文件中读取到内存,或者将内存中的数据写入到磁盘...
(1)read
函数原型
ssize_t read(int fd, void *buf, size_t count);
用于读取文件中的数据到内存中
参数
fd:open调用成功后返回的文件描述符,它和某一个磁盘文件形成一个映射关系,即背后是一个磁盘文件或设备文件buf:用户存放读取的数据的缓存count:buf的内存大小,用于表示最大读取的字节数
返回值
- 大于0的整数:表示从文件中读取的字节数
- 0:表示文件读完了
- -1:表示文件读取失败
(2)write
函数原型
ssize_t write(int fd, const void *buf, size_t count);
参数
类比read函数,根据类比推理可知write各个参数的含义
返回值
类比read...
3.文件的其他操作
通过文件的打开open、read、write和close四个函数,我们可以实现对文件的大部分操作了,但假如我们希望自由地读取文件数据,比如读取到文件末尾后,用户又向折回去,这个时候应该怎么办呢?
在私有制的市场经济中,有需求就有市场,换句话说:有需求就有供给,因此有需求就有市场。同样的道理,为了解决上述的用户需求,Linux系统提供了lseek函数来解决用户需求
(1)lseek
通过上文分析我们知道:lseek具备在文件数据中“自由运动”的魔力,现在咱们就来揭晓lseek背后的原理。
其实lseek函数的功能就是一个指向文件数据字节的指针,这个指针能够顺着文件数据来回游荡,像一个幽灵一样地游荡...
函数原型
off_t lseek(int fd, off_t offset, int whence);
参数
- fd:文件描述符, open() 函数的返回值
- offset:偏移量,依赖于第三个参数
- whence:从哪里开始偏移,SEEK_SET(文件首)、SEEK_END(文件尾部)、SEEK_CUR(当前文件指针处)
说明:当whence是SEEK_END是,offset常常设置为负数
返回值
- 大于0的整数:表示文件指针距离文件首的距离(字节数),即总的偏移量
- -1:表示函数调用失败
2.文件拓展
相信,上过公共课的同志都有一个体会:抢座位。对没错,在计算机系统中也有这样的操作,比如,使用某度网盘下载一个10GB的文件,点击下载之后,操作系统会首先从磁盘中创建一个对应大小的拓展文件,然后再慢慢悠悠、磨磨唧唧地下载这个大文件。这样子就避免了某些特殊情况的发生:假如我剩余的磁盘只有9.9GB,在下载10GB的文件一股脑地下载,下到9.9GB的时候发现没地方了,特别是没有VIP的某度用户,将面临十分崩溃的境况...
可以用一句十分通俗易懂的古语来总结文件拓展:先占茅坑后xx
(1)lseek实现文件拓展
lseek(fd, 1000, SEEK_END);
write(fd, " ", 1);
(2)truncate/ftruncate
这两个函数可以实现文件的截断和拓展
truncate:
int truncate(const char *path, off_t length);
-
path:要截断或拓展的文件名
-
length:文件的最终大小,当文件原字节数size>length时,文件被截断;当文件原字节数size<length时,文件被拓展
-
返回值:成功返回0,失败返回-1
ftruncate:
int ftruncate(int fd, off_t length)
- fd:open函数打开的文件描述符
- length:文件的最终大小,类比truncate的length参数
- 返回值:成功返回0,失败返回-1