目录
一、linux文件i/o概述
1、简介
2、文件和目录
3、系统调用和标准库函数库
二、底层文件访问
1、文件描述符
2、open
3、close
4、write
5、read
6、文件的定位 & lseek
7、fstat,stat,lstat
8、access
9、chown
10、chomd
11、rename
12、dup
13、flock
一、linux文件i/o概述
1、简介
在Linux中,几乎任何事物都可以用一个文件来表示,或者通过特殊的文件提供支持。
文件为操作系统服务和设备提供了一个简单而一致的接口。
大多数Linux文件I/O只需用到5个函数:open、read、write、lseek和close。
使用stat、access等其它I/O函数可以获取或设置文件的状态和权限等信息。
目录文件有一些简单而特殊的编程接口。
2、文件和目录
文件的属性(即
“
管理信息
”
)被保存在文件的索引节点(inode)中。
索引节点是文件系统中的一个特殊数据块,用以保存文件自身的属性。
文件使用的设备号
索引节点号
文件访问权限和文件类型
文件的硬连接数
所有者用户ID
组ID
设备文件的设备号
文件大小(单位为字节)
包含该文件的磁盘块的大小
该文件所占的磁盘块
文件的最后访问时间
文件的最后修改时间
文件的状态最后改变时间
目录是用于保存其他文件的节点号和名字的文件,是将文件的名称和它的索引节点号结合在一起的一张表。
目录中每一对文件名称和索引节点号称为一个“
连接
”
。
目录文件中的每个数据项都是指向某个文件节点的连接。
磁盘中的普通文件和目录文件都有相应的磁盘区域存储数据。这些数据是存储在由索引节点指定的位置上的。
特殊文件(如设备文件)不具有相应的磁盘存储区域。
硬件设备在Unix/Linux中通常被映射为文件,即设备文件。设备文件放在/dev目录下.
硬件设备可分为字符设备和块设备.
终端设备
一种字符设备,有多种类型.
简称tty,tty是 Teletype的缩写.
几个重要的设备文件
控制终端 (/dev/tty)
代表进程的控制终端(键盘和显示屏或键盘和窗口)。
不是物理意义上的终端,/dev/tty映射到当前的设备。
在控制台界面下(即字符界面下),映射到dev/tty1-6上。
在图形界面(XWindows),映射到/dev/pts伪终端上。
使用命令
“
ps -ax
”
可查看进程与哪个控制终端相连。
使用命令
“
tty
”
可以查看它具体对应哪个实际终端设备的设备文件。
3、系统调用和标准库函数库
系统调用是UNIX/Linux内核直接提供的编程接口,在内核空间运行。
C语言标准函数库是由一些函数构成的集合,完全运行在用户空间。
直接使用底层系统调用进行I/O操作的效率较低。
执行系统调用时,Linux必须从用户空间切换到内核空间,然后再切换回来。
硬件会限制系统调用一次须读写的数据块大小,如块设备。
应让每次系统调用完成尽可能多的工作。
C语言标准函数库带缓冲机制。
有关系统调用和标准函数库的文档一般分别放在手册页的第2和第3节。
二、底层文件访问
1、文件描述符
一个非负整数。对于内核而言,所有打开的文件都由文件描述符引用。
当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。
从内核源码的角度看,文件描述符其实是当前进程所打开的文件结构数组的下标。
3个特殊的文件描述符(头文件<unistd.h>)
0 STDIN_FILENO 标准输入
1 STDOUT_FILENO 标准输出
2 STDERR_FILENO 标准错误输出
2、open
打开或创建一个文件.
pathname 要打开或创建的文件的名称.
flags 由下列一个或多个常数进行或运算构成.
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读、写
O_APPEND 每次写时追加到文件的尾端
O_CREAT 若此文件不存在则创建它,应结合第三个参数mode 使用
O_EXCL 给合O_CREATE,当文件不存在时,才创建文件。
O_TRUNC 如果此文件存在而且可写,则将其长度截短为0。
mode 存取许可权位,一个32位无符号整数,仅当创建新文 件时才使用。最终文件权限受系统变量umask限制, 为 “
mode & ~
umask
”。由以下值按位或得到。
S_IRUSR 文件所有者-读
S_IWUSR 文件所有者-写
S_IXUSR 文件所有者-执行
S_IRGRP 组用户-读
S_IWGRP 组用户-写
S_IXGRP 组用户-执行
S_IROTH 其他用户-读
S_IWOTH 其他用户-写
S_IXOTH 其他用户-执行
返回值
成功时返回一个文件描述符(非负整数)。
失败时返回-1,并设置全局变量errno指明失败原因。
由open返回的文件描述符一定是最小的未用描述符数字。
3、close
关闭已打开的文件。
filedes 待关闭的文件描述符。
返回值 成功时返回0,失败时返回-1。
调用close函数后,终止了文件描述符与文件之间的关联,被关闭的文件描述符重新变为可用。
同时,释放了该进程加在该文件上的所有记录锁。
当一个进程终止时,它所打开的所有文件都将由内核自动关闭。
4、write
向已打开的文件中写入数据
fd 文件描述符
buf 待写入文件的数据的缓冲区,常量指针
count 待写的字节数
返回值 成功为已写的字节数;出错为- 1,错误值记录在errno。
ssize_t在32位机中是int,在64位机中是long int。
5、read
从已打开的文件中读取数据.
fd 文件描述符.
buf 用于放置读取到的数据的缓冲区.
count 要读取的字节数.
返回值 若成功为已读取的字节数(0表示已到达文件尾); 若出错为-1,错误值记录在errno.
6、文件的定位 & lseek
每个已打开的文件都有一个与其相关联的“当前文件位移量”。
通常,读、写操作都从当前文件位移量处开始,并在读、写完成后使位移量增加所读或写的字节数。
当打开一个文件时,如果指定O_APPEND选项,该位移量被设置为文件的长度,否则该位移量被设置为0。
调用lseek函数显式地定位一个已打开文件的“当前文件位移量”。
fd 文件描述符
offset 位移量,相对于whence参数
whence 指定位移量相对于何处开始,可取三个常量值.
返回值 若成功为当前读写位置相对于文件头的位移量;若出错 为-1,错误值记录在errno.
lseek 仅将当前的文件位移量记录在内核变量内,并不引起任何I/O操作。
示例
7、fstat,stat,lstat
读取文件的属性.
file_name 文件名.
filedes 文件描述符。
buf 文件信息结构缓冲区.
返回值 成功为0;若出错为- 1,错误值记录在errno.
当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息。
struct stat
struct stat {
dev_t st_dev; /* 保存本文件的设备的ID */
ino_t st_ino; /* 与文件关联的索引节点号(inode)*/
mode_t st_mode; /* 文件权限和文件类型信息 */
nlink_t st_nlink; /* 该文件上硬链接的个数 */
uid_t st_uid; /* 文件所有者的UID号 */
gid_t st_gid; /* 文件所有者的GID号 */
dev_t st_rdev; /* 特殊文件的设备ID */
off_t st_size; /* 文件大小(字节数) */
blksize_t st_blksize; /* 文件系统I/O的块大小*/
blkcnt_t st_blocks; /* 块数(512字节的块)*/
time_t st_atime; /* 最后访问时间 */
time_t st_mtime; /* 最后修改时间 */
time_t st_ctime; /* 最后状态改变时间 */
};
一般用法
8、access
判断文件是否存在及是否可访问
pathname 文件名.
mode 测试项.
返回值 成功(具有所有测试项权限)为0;若出错为- 1,错误 值记录在errno。
示例
9、chown
改变文件的所有者.
path 文件名。
owner 新文件所有者的用户ID,-1表示保持所有者不变。
group 新文件所属组的ID,-1表示保持所属组不变。
fd 文件描述符。
返回值 成功为0;若出错为- 1,错误值记录在errno.
当文件是一个符号链接时,lchown改变的该符号链接本身的所有者,而chown改变的是该链接指向的文件的所有者。
只有root用户才可以使用这些函数来改变任意文件的所有者和所属组,而普通用户只能改变属于自己的文件的所属组,并且指定的所属组只能是用户自身所在组之一。
示例
10、chomd
改变文件的访问权限.
path 文件名.
mode 文件的权限,由一组八进制数的“或”运算构成,其中的各个位表 示一种权限,称权限位。同open函数的struct stat结构参数的 st_mode.
fd 文件描述符.
返回值 成功为0;若出错为- 1,错误值记录在errno.
权限位 | 八进制常量值 | 含义 |
S_ISUID | 04000 | 设置SUID |
S_ISGID | 02000 | 设置SGID |
S_ISVTX | 01000 | 设置粘滞位 |
S_IRUSR | 00400 | 文件所有者可读 |
S_IWUSR | 00200 | 文件所有者可写 |
S_IXUSR | 00100 | 文件所有者可执行 |
S_IRGRP | 00040 | 文件所属组可读 |
S_IWGRP | 00020 | 文件所属组可写 |
S_IXGRP | 00010 | 文件所属组可执行 |
S_IROTH | 00004 | 其他用户可读 |
S_IWOTH | 00002 | 其他用户可写 |
S_IXOTH | 00001 | 其他用户可执行 |
示例
11、rename
重命名文件或目录
oldpath 旧文件名.
newpath 新文件名.
返回值 成功为0;若出错为- 1,错误值记录在errno.
旧文件名、新文件名与返回结果的关系.
oldpath | newpath文件不存在 | newpath为普通文件 | newpath为目录文件 |
普通文件 | 文件被重命名,返回成功 | 原newpath文件被删除,oldpath文件被重命名为newpath,返回成功 | 返回错误 |
目录文件 | 文件被重命名,返回成功 | 返回错误 | newpath目录文件为空则该目录被删除,oldpath目录被重命名为newpath,返回成功。否则返回错误。 |
12、dup
复制文件描述符.
oldfd 旧文件描述符.
newfd 新文件描述符.
返回值 成功为新文件描述符;出错为- 1,错误值记录在errno.
注意
复制得到的文件描述符和旧文件描述符将指向同一个打开的文件。
dup函数返回的是最小未用的文件描述符,而dup2函数返回的是预先指定的文件描述符newfd。
如果newfd正在使用,则会先关闭newfd。如果newfd与oldfd一样,则关闭该文件正常返回
13、flock
上锁或解锁一个文件.
fd 文件描述符.
operation 上锁或解锁方式:
LOCK_SH 共享锁
LOCK_EX 独占锁
LOCK_UN 解锁
返回值 成功为0;出错为- 1,错误值记录在errno.
注意
:
一个进程对一个文件只能有一个独占锁,但可以有多个共享锁。
上锁的作用只有在别的进程要对该文件上锁时才能表现出来。
对文件的操纵本身与锁其实没有什么关系!无论文件是否被上锁,用户都可以随便对文件进行正常情况下的任何操纵。
上锁文件的目的是为了同步多个进程之间的操作。
默认情况下,flock是阻塞式的。如果要进行非阻塞式调用, 应将operation参数与常量“LOCK_NB” 进行二进制“或”。
非阻塞式调用flock后,flock会立即返回-1,并且errno的值将为EWOULDBLOCK。