<Uinx 环境高级编程笔记>
1 常用的I/O
打开文件
int open( const char * pathname, int flags);
int open( const char * pathname,int flags, mode_t mode);
返回值:文件描述符,一个整数。
头文件:#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h>
第一个参数: 欲打开的文件路径
flags: 访问模式,O_RDONLY, O_WRONLY, O_RDWR, O_CREAT,O_EXCL(判断文件是否存在), O_TRUNC, O_NONBLOCK(非阻塞方式打开), O_APPEND.
mode:只有在建立新文件是才会生效。指定新建文件的属性。
open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode) 等价与 create(pathname, mode)
create的不足是只能也只写文件方式创建文件。即如果要创建一个临时文件可读可写,需要create, close然后再open。
关闭文件
关闭文件很简单, close函数,传给它要关闭的文件描述符就可以了。
当一个进程终止时,它所有打开的文件都由内核自动关闭。
文件定位
我们可以从文件的任何位置开始读写,这需要一个移动到指定位置的函数,就是lseek。
off_t lseek(int fildes,off_t offset ,int whence)
头文件:<sys/types.h> <unistd.h>
whence: 移动的参照位置,SEEK_SET(从文件开始), SEEK_CUR(从当前位置), SEEK_END(从文件尾)
offset: 偏移量
返回值: 文件的当前位移量
例子:假设文件内容为Hello, 那么文件长度为5
curpos = lseek(fd, 0, SEEK_SET); //curpos为0
curpos = lseek(fd, 0, SEEK_CUR); //curpos为0
curpos = lseek(fd, 0, SEEK_END); //curpos为5
curpos = lseek(fd, 5, SEEK_END); //curpos为10
curpos = lseek(fd, -11, SEEK_END); //curpos为-1(error)
文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,
并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被读为0。
od -c file: 以字符方式打印文件内容。
读文件
ssize_t read(int fd,void * buf ,size_t count);
头文件:<unistd.h>
返回实际读到的字节数。
从终端设备读时,通常一次最多读一行。
写文件
ssize_t write (int fd,const void * buf,size_t count);
copy的一个简单实现
View Code
#define BUFFSIZE 8192 int main(int argc, char **argv) { if (argc != 3) { printf("Usage: %s file1 file2\n", argv[0]); exit(1); } int fd1, fd2; fd1 = open(argv[1], O_RDONLY); fd2 = open(argv[2], O_WRONLY|O_CREAT | O_TRUNC, FILE_MODE); char s[BUFFSIZE]; int n; printf("%d %d\n", fd1, fd2); while ( (n=read(fd1, s, BUFFSIZE)) > 0) { printf("%s\n", s); write(fd2, s, n); perror("write"); } close(fd1); close(fd2); }
2 I/O的效率
不同的I/O长度对读写时间有影响。
在上面的程序中,BUFFSIZE 会影响复制的效率。系统CPU时间的最小值开始出现在BUFFSIZE为8192处,继续增加缓存长度对此时间并无影响。--《Unix环境高级编程》
3 文件共享
每个打开的进程也下面三个结构相关
1 文件描符表 -- 包括文件描述符标志、指向一个文件表项的指针。
2 每一个打开的文件都有一张文件表 -- 包括文件状态标志、当前文件位移量、指向文件v节点的指针。
3 每个打开的文件都有一个v节点结构。-- v节点包含了文件类型和对此文件进行各种操作的函数的指针信息。
v节点还包含了该文件的i节点。i节点包含了文件的所有者、文件长度、文件所在的设备。
v节点一般是共享的。文件表项一般是独立的 -- 这种安排使每个进程都有它自己的对该文件的位移量。
int newfd= dup(oldfd)
dup之后使用同一份文件表。newfd和oldfd指的是同一个文件,共享所有的锁定、读写位置,权限或旗标。
fcntl
可以用来改变已打开文件的性质。也可用来获得打开文件的各种属性。
int fcntl(int fd , int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock * lock);
val = fcntl(fd, F_GETFL, 0);
accmode = val & O_ACCMODE;
if (accmode == O_RDONLY) printf("read only");
else if (accmode == O_WRONLY) printf("write only");
else if (accmode == O_RDWR) printf("read write");
a.out 0</dev/tty
表示在文件描述符0上打开读
a.out 1>temp.foo
表示在文件描述符1上打开写,写到标准输出的都会转移到文件temp.foo
a.out 2 2>>temp.foo
表示在文件描述符2上打开写,添加到文件尾。
a.out 5 5 <>temp.foo
表示在文件描述符5上打开temp.foo以供读写。
read, write都因系统调用而进入内核,所以称这些函数为不带缓存的I/O函数。
如启用添加标志打开文件,便只能在末尾写。但可以在任意位置读。有写操作时,会自动定位到文件尾进行写操作。