1. 我目前在Linux中运行的程序通常是在Shell 之上运行的,Shell 已经设定好了 standard input(键盘) 和 standard output(显示器).
2. 许多程序都默认 standard input 的 file descriptor 是 0, standard output 的 file descriptor 是 1。在<unistd.h>中定义了两个常量来表示这两个 file descriptor,一个是STDIN_FILENO,另一个是STDOUT_FILENO.
3. 当一个进程结束的时候,由这个进程所打开的所有 file 都会由 kernel 自动关闭。
4. read() 和 write() 这两个函数是 unbuffered I/O,而 standered I/O 是 buffered I/O.
5. Unix中的所有东西都是文件。对于一个打开的文件,Unix 内核使用三种数据结构联合起来描述一个打开的文件:
· 每个进程在进程表(process table)中都会占有一个条目,在这里面就放着打开的file 的 descriptor。对于每一个descriptor,有两个描述它的东西:
一个是file descriptor flag(说明这个file的状态,是close 、on 或者 exec);
还有一个是指向file table entry的指针。
· 对于所有打开的文件,内核维护着一个 file table,这里面每一个条目包括三个部分:
file satus flags(read, write, append, sync, nonblocking);
current file offset
执行v-node table的指针
· 每一个打开的文件有一个v-node talbe表示这个文件的一些信息。
6. lseek()这个函数就是设置file table 的current file offset。它也仅仅只是对这个值进行设置,并不会进行真正的I/O操作。
7. 如果使用write() 对文件进行写操作,写入多少bytes, current file offset 就会加上多少。当current file offset 的值要比i-node 中的current file size还大的时候,这个值就会变得和current file offset一样大。
8. 这里稍微讲到了一些原子操作的东西。如果一个操作需要两个函数来完成,那么多个进程进行这个操作就有可能出问题。比如“查找一个文件的末尾”和“往文件中写入”这两个操作,需要使用lseek() 和 write()这两个函数。如果这不是一个原子操作,那么很可能会出问题。原子操作就表明,这两个函数,要么全部执行,要么不执行,不会出现只执行lseek()这一个函数的情形出现。
9. 当使用open() 函数打开一个文件的时候,这个函数所返回的file descriptor保证是系统之中可以使用的最小的file descriptor。
使用dup() 函数复制一个 file descriptor的时候,它所返回的 file descriptor 也能保证是系统之中可以使用的最小的file descriptor的值。
10. Unix系统中一般都会有buffer cache 或者 page cache,当向磁盘读写的时候,大部分I/O都要经过这些cache。这样一些数据就会以queue的形式保存在 kernel中,就需要一种方法来把cache中的东西和磁盘中的文件进行同步。这就需要使用sync() 函数 或者 fsync() 函数。
11. 使用F_GETFL找出file status flags:
val = fcntl(atoi(argv[1]), F_GETFL, 0)
12. Normally in the UNIX System, a write only queues the data for writing; the actual disk write operation can take place sometime later. IF WE SET O_SYNC, this causes each write to wait for the data to be written to disk before returning.