您的位置:首页 > 编程语言

unix环境高级编程 学习笔记3

2011-11-14 19:47 330 查看
 

第三章  文件IO[仅作学习笔记,其中可能有误解]

1.	unix 系统中的IO是POSIX.1和Single UNIX SPecification中的一部分,不是ISO C的组成部分。
这一章的IO函数是不带缓冲的,与ISO(标准)C的带缓冲IO相对应。

2.	对于内核来讲,所有打开的文件都通过文件描述符[非负整数]来引用。当打开一个文件时,有内核返回一个描述符给进程。

3. 	0与标准输入相关联 1与标准输出相关联 2与标准出错输出相关联
为避免幻数,用符号常量来替代:STDIN_FILENO STDOUT_FILENO STDERR_FILENO.
文件描述符为0~OPEN_MAX,则一个进程打开的文件描述符是有限的

4. 	创建文件
#include <fcntl.h>
int open(const char * pathname, int oflag, ... /*mode_t mode*/);
// oflag: 	O_RDONLY O_WRONLY O_RDWR
//	 	 	O_APPEND O_CREAT O_DSYNC O_EXCL O_NOCTTY
// 		 	O_NONBLOCK O_RSYNC O_SYNC O_TRUNC
// mode:	S_IS[UG]ID, S_ISVTX, S_I[RWX](USR|GRP|OTH)
// *****************************************************
// 仅当在创建文件时才需要第三个参数

oflag 为各选项的或操作结合而成,其中前三个只能选其一,其他任选
要想判断一个文件是否存在,可同时使用O_CREAT和O_EXCL,若存在则会出错,否则创建

5. 	创建文件
#include <fcntl.h>
int create(const char *pathname, mode_t mode);
// mode: S_IS[UG]ID, S_ISVTX, S_I[RWX](USR|GRP|OTH)
该函数相当于 open(pathname, O_WRONLY |O_CREAT | O_TRUNC, mode);
故限制性较大

6.	关闭文件
#include <unistd.h>
int close(int filedes);
6.1	关闭文件时会释放该进程加在该文件上所有的记录锁
6.2 进程结束时,内核会关闭进程打开的所有文件

7.	文件偏移
#include <unistd.h>
off_t lseek(int filedes, off_t offset, int whence);
7.1	off_t 与标准C中的fseek(FILE * fd, long offset, int whence);的long形成对比
7.2 管道、FIFO、网络套接字是不能设置偏移量的,会返回-1,并且设置errno为ESPIPE
7.3 偏移量有可能是负数,因此测试是否可设置偏移量时应该判断返回值是否为-1,而不是小于0
7.4	文件偏移量有可能大于当前文件长度,从而形成空洞,空洞不要求在磁盘上占用存储区
书中举了一个例子,两个长度相同的文件,无空洞的比有空洞的占用了更多的存储区

8.	读取数据
#include <unistd.h>
ssize_t read(int filedes, void * buf, size_t nbytes);
// 返回值:成功则返回读到的数据字节数,到尾部则0,出错-1
8.1	有多种情况实际读到的数据字节数比要求读的nbytes少:
+	读普通文件,读到要求的字节数前已经到文件尾,下一次则返回0
+	从终端读,通常一次一行
+ 	socket中的网络缓冲结构可能小于所要读的
+	管道或FIFO中包含的字节比要求的少
+ 	有信号中断

9.	写数据
#include <unistd.h>
ssize_t write(int filedes, const void * buf, size_t nbytes);
// 返回值:成功则返回已写的数据字节数,出错-1
9.1	返回值通常与nbytes相同,否则表示出错了,常见原因是磁盘满了,或超过文件长度限制

10 IO效率
每次调用read和write都是系统调用,用户态与核心态间的上下文切换是比较耗时的,我们应当选择
比较好的nbytes来保证IO的效率,测试的结果是当设置的缓冲区为4096[文件系统ext2的块大小]时,
效率已经很好,在增加缓冲区时间也没有太大影响

11.	文件共享
11.1	UNIX系统支持不同进程共享打开的文件。
11.2	内核使用了三种数据结构表示打开的文件,这也决定了文件共享的特点
+	进程表 [fd|文件指针(指向文件表)]
+	文件表 [文件状态标志|当前文件偏移量|v节点指针]
+	v节点  [v节点信息|i节点信息|当前文件长度]
11.3 	两个独立的进程打开同一个文件
+	此时进程表项指向不同的文件表,但文件表指向同一v节点,则inode
此时要保证共享文件能正确操作:
此时通过原子操作来保证,每次写完和设置文件偏移量会保证是在同一个原子操作,
从而保证正确共享
11.4 	两个独立的进程打开同一个文件
#include <unistd.h>
int dup(int filedes);
#include <unistd.h>
int dup2(int filedes, int filedes2);
+	dup用于复制文件描述符号,dup2复制filedes到filedes2
+	通过dup会使得进程表中有两个描述符使用同一文件表
如何处理:
+

12 		文件系统与缓冲区高速缓存的一致性
12.1 	内核中有缓冲区高速缓存或页面高速缓存,[开头说本章的IO是不带缓冲的,是指在用户态没缓冲吗?]大多数磁盘IO通过缓冲进行,当写文件数据时,内核将数据复制缓冲区,等待缓冲区满或内核需要重用缓冲区时候,才将该缓冲区排入输出队列,然后等待到队首,才进行磁盘IO--这叫延迟写。
12.2	为保证磁盘中实际文件与高速缓存的一致性,提供了如下函数:
+
#include <unistd.h>
int fsync(int filedes);
只对filedes有效,且等待实际磁盘操作完成。处理数据和文件属性。
+
#include <unistd.h>
int fdatasync(int filedes);
只对filedes有效,且等待实际磁盘操作完成。但只处理数据。
+
#include <unistd.h>
void sync(void);
只是将修改过的块缓冲区写入输出队列,不等实际磁盘操作。update守护进程每30调一次,sync			 命令也是调用这个函数。

13.		改变已经打开文件的属性
13.1	提供的函数:
#include <fcntl.h>
int fcntl(int filedes, int cmd, ... /* int arg */);
// cmd: F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL
// 		F_GETOWN, F_SETOWN, F_GETLK, F_SETLK, F_SETLKW
这个函数很复杂,知道是处理已打开文件的属性,其他的选项用到再查吧。
FD_CLOEXEC表示在调用exec时文件描述符是否还有用。
fcntl用于记录锁

14.		IO的其他操作
14.1	ioctl函数
#include <unistd.h>
#include <sys/ioctl.h>
#include <stropts.h>
int ioctl(int filedes, int request, ...);
现在已经有部分函数来替代iocntl了.这个函数通常是对设备[终端]的一些操作。
ioctl用于STREAMS I/O.

15.		/dev/fd/n等价于文件描述符n
[转载请表明]http://blog.csdn.net/kangquan2008


[转载请表明]http://blog.csdn.net/kangquan2008
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息