3.系统调用函数,对文件的操作
系统调用:
定义:操作系统把它具有的功能列成一张表,然后给每一个功能取一个编号,当用户层需要调用某个系统功能时,只需要向内核发送对应的编号即可。
1.Linux和Unix系统的绝大多数功能都是通过系统调用形式提供的,不是通过函数形式调用,当需要执行这些功能的时候,可以向内核发送一个编号,那么内核就会把对应的系统调用执行。
2.系统调用是以标准C语言的形式提供的,但是它不属于C语言.
3.一般程序员所写的代码都工作在用户态,但系统调用工作在内核态,用户态是不能直接访问内核中的数据,必须经过系统调用才行。
一切皆文件
在Unix和Linux系统中基本上把所有的资源都抽象成了文件,包括网络,打印机,串口,鼠标键盘,显示器,都可以像操作文件一样来控制硬件
文件分类:
目录文件
设备文件 /dev
普通文件
一般操作文件需要的操作
打开 读 写 设置 关闭
常见的文件相关的系统调用
文件描述符:是一个非负的整数,功能类似于标准C中的FILE*文件指针,它代表内核中一个打开的文件
打开文件
int open(const char *pathname, int flags);
pathname:文件的路径
flags:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 创建
O_EXCL 文件已存在,则创建失败
O_NOCTTY
O_TRUNC 打开时是否清空
O_APPEND打开时以追加的方式打开
返回值:
文件描述符,是一个无符号整数,这个整数对应一个内核对象,对程序来说它的值是多少无所谓,把它当作操作文件的令牌即可。
特殊的文件描述符:
0 标准输入
1 标准输出
2 标准错误
int open(const char *pathname, int flags, mode_t mode);
mode是用来给文件设置权限的,但是通过mode设置的权限会被权限屏蔽码过滤,权限设置是以八进制方式设置的。
umask设置,查看权限屏蔽字的
关闭文件:
int close(int fd)
fd:文件描述符
返回值:0表示成功,1表示失败
创建文件:
int creat(const char *pathname,mode_t mode);//底层调用的是open
pathname:文件路径
mode:文件权限,会受到文件屏蔽字的过滤,创建文件时候需要设置文件权限 0mmm
creat是调用open来实现的
返回值:文件描述符
写文件:
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符
buf:要写入的首地址
count:希望写入的字节数
返回值:实际写入的字节数
读文件:
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符
buf:数据存放的位置
count:希望读入的字节数
返回值:实际读入的字节数
练习:实现cp命令。
文本文件的数据读写
1.结构体以文本形式写入文件中
a.准备缓存区
b.把结构体使用sprintf拼接到缓冲区中
c.把缓冲区里的内容写入文件
2.从文本文件中读取结构体
a.准备缓冲区
b.把数据从文件中读取到缓冲区中
c.使用sscanf从缓冲区中解析结构变量
文件位置指针:
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符
offset:偏移值
whence:基准值
返回值:调整后的文件位置指针所在的位置
lseek 对应 fseek
ftell 没有对应,lseek(fd,0,SEEK_CUR);就可以实现这个功能,rewind同理
文件黑洞:lseek是可以把文件位置指针调整到文件的末尾之后的位置,形成的空白的东西叫做文件黑洞,文件黑洞是没有数据的,也不占用硬盘空间,但是回计算在文件大小中。
标准IO与系统IO
例子:把所有short的值写入到文件中
标准IO在进行数据读写时,不会把数据直接写入到文件中,而是先写入缓冲区,减少了进出内核的速度,这样就大大提高了文件的读写速度。
系统IO在不使用缓冲区的情况下,速度不如标准IO。因此在使用系统IO读写文件时一定要为它分配一块缓冲区,大小最好为一页(4K/4096byte)。
文件描述符的复制:
#include <unistd.h>
int dup(int oldfd);
oldfd:想要复制的文件描述符
特殊的几个描述符:
0 = STDIN_FILENO
1 = STDOUT_FILENO
2 = STDERR_FILENO
返回值:最小的没有使用过的文件描述符
int dup2(int oldfd, int newfd);
oldfd:想要被复制的文件描述符
newfd:指定的文件描述符,如果已经被占用则关闭,再复制
fcntl
1.复制文件描述符
2.获取文件权限
3.设置文件的权限
4.用此函数操作硬件设备时,fcntl的功能是由硬件驱动决定的,功能可以自定义
文件同步
sync 同步所有打开的文件到磁盘
fsync 同步指定的文件到磁盘
fdatasync 同步指定的文件,但是只同步数据
umask/access
设置权限屏蔽码,只对当前进程有效
access 查询文件的权限
F_OK
R_OK
W_OK
X_OK
chmod/fchmod/chown/fchown/lchown
chmod/fchmod 修改文件的权限
chown/fchown/lchown 修改用户id和组id
lfunc只对软连接文件有效,不针对目标
truncate/ftruncate
文件的截取,把文件多余的内容去掉
link/unlink/remove
link创建链接文件,创建的是硬链接
unlink珊瑚链接,一个普通文件其实就是一块数据区,对应了一个硬链接,当一个文件的链接数减为0的时候这个文件就被删除了,此函数也可以用来删除文件。
remove用来删除文件,与unlink功能类似
rename重命名
symlink/readlink
symlink 创建软链接
readlink 读取软链接
而使用open打开软链接文件,打开的是它的链接目标,所以读取到的不是链接文件的内容
mkdir/rmdir
mkdir创建目录,创建的目录要有执行权限,否则无法打开
rmdir只能用来删除空目录,操作系统没有提供删除非空目录的系统调用。
练习:实现rm -rf的功能
目录流的操作
opendir/fopendir 打开一个目录流 返回DIR*
readdir 从目录流中读取一个对象 struct dirent*
closedir 关闭目录流
seekdir 设置目录流位置
telldir 返回当前目录流的位置
rewinddir 把目录流的位置调整到开头
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
练习:实现ls -l的功能
获取用户组信息getpwuid/getgrgid
getpwuid:使用用户ID获取用户信息
struct passwd *getpwuid(uid_t uid);
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
getgrgid:使用组ID获取组信息
struct group *getgrgid(gid_t gid);
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
练习
附件列表