Unix I/O
输入/输出(I/O)是在主存和外部设备之间复制数据的过程。输入操作是从I/O设备复制数据到主存,输出操作是从主存复制数据到I/O设备。
一切皆文件。所有的I/O设备都被模型化为文件,所有的输入输出都被当作对相应文件的读和写来执行。
文件描述符(file descriptor):内核返回一个小的非负整数叫做描述符。内核利用它来标识文件。
Linux shell创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0),标准输出(描述符为1),标准错误(描述符为2)。
关闭文件后,内核会释放数据结构,并将该文件的描述符恢复到可用的描述符池中。
文件
每个Linux文件都有一个类型来表明它在系统中的角色:
-
普通文件(regular file):包含任意数据。包括文本文件和二进制文件。
-
目录(directory):是包含一组链接的文件,每个链接都将一个文件名映射到一个文件。
· 链接(link):链接是对文件的引用。在 Linux 中,链接可以如同原始文件一样来对待。链接可以与普通的文件一样被执行、编辑和访问。对系统中的其他应用程序而言,链接就是它所对应的原始文件。链接不是副本,当通过链接对文件进行编辑时,编辑的实际上是原始文件。有两种类型的链接:硬链接和软链接(符号链接)。
硬链接:用ln [源文件] [目标文件]
命令可以生成一个硬链接。
硬链接只能引用同一文件系统中的文件,不能对目录文件进行创建硬链接操作。硬链接文件不能跨文件系统。
硬链接文件不占用存储空间,它引用的是文件在文件系统中的物理索引(inode)。
修改源文件或者目标文件, 对应另外一个文件也会发生相应修改。
当移动或删除原始文件时,硬链接不会被破坏,因为它所引用的是文件的物理数据而不是文件在文件结构中的位置。
硬链接的文件不需要用户有访问原始文件的权限,也不会显示原始文件的位置,这样有助于文件的安全。
软连接:用ln -s
命令可以生成一个软连接。
软链接文件只是其源文件的一个标记,当删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但却不能查看软链接文件的内容了。
链接文件甚至可以链接不存在的文件,这就产生一般称之为”断链”的现象,链接文件甚至可以循环链接自己。类似于编程语言中的递归。
在对符号文件进行读或写操作的时候,系统会自动把该操作转换为对源文件的操作,但删除链接文件时,系统仅仅删除链接文件,而不删除源文件本身。 -
套接字(socket):是用来与另一个进程进行跨网络通信的文件。
可以用mkdir命令创建一个目录,用ls查看其内容,用rmdir删除该目录。
下图用mkdir命令创建了一个名为direc的目录,又用rmdir删除了该目录
ls -l
命令可查看当前目录下所有可见文件的详细属性。
以all目录为例:
文件属性: 第①个字符:-表示普通文件,d表示目录文件; -代表无权限,r代表具有可读权限,w代表具有可写权限,x代表具有可执行权限
drwxr-xr-x,第①个字符d表示该文件是一个目录。rwx表示(拥有者)属主权限,可读、可写、可执行权限。r-x表示(拥有者所在组的成员)组权限,可读、可执行。r-x表示其他用户权限,可读、可执行。
文件硬链接数量:31
所有者:tangein
所属用户组:tangein
文件大小:4096 byte
修改时间:2019年1月22日
文件名:all
chmod命令可改变文件属性。+ 表示增加权限,- 表示取消权限,= 表示唯一设定权限。
打开和关闭文件
open函数
-
头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> -
定义函数
int open(char *filename, int flags);
int open(char *filename, int flags, mode_t mode); -
参数说明
pathname 指向欲打开的文件路径字符串
flags 指明进程如何访问文件:
· O_RDONLY 只读
· O_WRONLY 只写
· O_RDWR 可读可写
· O_CREAT 如果文件不存在就创建它的一个截断的(空)文件。
· O_TRUNC 如果文件存在,就截断它。即如果文件存在且为普通文件,打开方式为可写(O_WRONLY或O_RDWR),则清空文件内容。
· O_APPEND 在每次写操作前,设置文件位置到文件的结尾处 -
返回值
若成功则为新文件描述符,若出错则为-1 -
函数功能
打开一个已存在的文件或创建一个新文件
close函数
-
头文件
#include <unistd.h> -
定义函数
int close(int fd); -
参数说明
fd 是要关闭的文件描述符 -
返回值
若成功则为0,若出错则为1 -
函数功能
关闭一个打开的文件 (关闭一个已关闭的描述符会出错)
#include "csapp.h"
int main()
{
int fd1,fd2;
fd1=Open("foo.txt",O_RDONLY,0);
Close(fd1);
fd2=Open("baz.txt",O_RDONLY,0);
printf("fd2=%d\n",fd2);
exit(0);
}
该程序的输出结果为 fd2=3
open函数总是返回最低的未打开的描述符。第一次调用open返回3,即fd1=3,调用close函数释放描述符3。因此再次调用open返回3,即fd2=3。
读和写文件
read函数
-
头文件
#include <unistd.h> -
定义函数
ssize_t read(int fd, void *buf, size_t n); -
参数说明
fd 是要读的文件描述符
buf 是要读入的内存位置
n 表示最多读入的字节数 -
返回值
若成功则为读的字节数,若EOF则为0,若出错则为-1 -
函数功能
从文件中读
write函数
-
头文件
#include <unistd.h> -
定义函数
ssize_t write(int fd, const void *buf, size_t n); -
参数说明
fd 是要写的文件描述符
buf 指向一段要写入的内存空间的首地址
n 表示最多写入的字节数 -
返回值
若成功则为写的字节数,若出错则为-1 -
函数功能
写到一文件中
读取文件元数据
stat和fstat函数
-
头文件
#include <unistd.h>
#include <sys/stat.h> -
定义函数
int stat(const char *filename, struct stat *buf);
int fstat(int fd, struct stat *buf); -
参数说明
stat函数以一个文件名filename作为输入,fstat函数以一个文件描述符fd作为输入,填写stat数据结构中的各个成员
struct stat{
dev_t st_dev;
ino_t st_ino;
mode_t st_mode; /* 文件访问许可位和文件类型 * /
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size; /* 文件的字节数大小* /
timestruc_t st_atim;
timestruc_t st_mtim;
timestruc_t st_ctim;
blksize_t st_blksize;
blkcnt_t st_blocks;
char st_fstype[_ST_FSTYPSZ];
}; -
返回值
若成功则为0,若出错则为-1 -
函数功能
检索关于文件的信息。
I/O重定向
dup函数和dup2函数
-
头文件
#include <unistd.h> -
定义函数
int dup(int fd);
int dup2(int oldfd, int newfd); -
参数说明
fd 是一个文件描述符
oldfd 是重定向后的文件描述符
newfd 是被覆盖的文件描述符 -
返回值
若成功则为非负的描述符,若出错则为-1 -
函数功能
复制一个现存的文件描述符;
复制描述符表表项oldfd到描述符表表项newfd,并覆盖newfd的内容
假设:描述符1对应文件A,描述符4对应文件B。A、B的引用计数都等于1
调用dup2(4,1)后,两个描述符都指向文件B。
此时文件A被关闭,并且A的文件表和v-node表表项都已经被删除了