- 论坛徽章:
- 0
|
在APUE第三节——File I/O 中,主要描述的是一系列的 I/O 函数,通过一些函数来进行文件的一些操作。
这些操作基本上用下面这几个系统函数:open, read, write, lseek, close。在这一章中所有的系统函数
都属于“非缓冲文件”(unbuffered I/O)。开头第2段文字有这样一句话来描述 "unbuffered" : The term
unbuffered means that each read and write invokes a system call in the kernel. 也就
是说这些函数都是直接调用内核中的系统函数,它完全没有经过“缓冲区”,直接调用了。所以,这样不经过
“缓冲区”速度就肯定比经过“缓冲区”快了。这篇学习笔记将对“缓冲文件系统”和“非缓冲文件系统”作一个
比较,当然,主要还是放在“非缓冲文件系统”方面来描述。
一、缓冲文件系统简要描述:
第一段简单说到了, “缓冲文件系统”的文件操作要经过“缓冲区”,那么具体如何操作呢?比如说最常用的
read 和 write。首先操作系统会在内存区域开辟一个缓冲区,顾名思义缓冲区就是用于缓冲的。如果要执行
read操作,那么先从磁盘那里把数据内容读入了缓冲区,然后等到把缓冲区装满之后,CPU再从缓冲区把数据
读入特定的变量。如果是写操作,刚好是反过来了,CPU先把数据一个个写进缓冲区里面,等到写满之后就把
缓冲区刚刚写进的数据写入到文件里面了。
ANSI C 中函数库支持“缓冲区文件系统”, 所以文件操作函数像 fopen, fclose, fread, fwrite等都是
属于缓冲I/O。这里不多说这些函数了。
二、非缓冲文件系统描述:
在ANSI C 中函数库支持“缓冲区文件系统”,但不支持“非缓冲文件系统”,“非缓冲文件系统”是POSIX.1
和 UNIX specification 的一部分。
前面说到了,非缓冲I/O是系统直接的输入和输出,它不经过“缓冲区”,所以从速度和效率方面来说就显得
快一些了。下面对几个基本的unbuffered I/O 函数的功能通过配合代码描述一下。
1. int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
man手册上提供的函数原型。pathname 是路径名,是文件打开或者新建的文件名字。参数 flags 是选择
的描述符。man手册上有句话这样描述flags:The parameter flags must include one of the
following accessmodes:O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file
read-only, write-only, or read/write, respectively.还有通过“位与”的模式来描述flags的,man手册上
都写得很具体了。比较上面两个open原型,发现第2个函数原型多了一个参数mode_t mode.有什么区别?
The argument mode specifies the permissions to use in case a new file is created. 所有只有当
是新建文件的时候,第3个参数才有它的作用,在手册上也一几个你列举了这个参数的一些值了。下面这样调用
open 就是等价于新建了一个文件:
open(pathname, O_WRONLY | O_CTREAT | O_TRUNC, mode);
2. ssize_t read(int fd, void *buf, size_t count);
ssize_t : functions that return a count of bytes(signed).
注意到第1个参数fd, 这是文件的描述符。对于内核来说,所有的文件都用文件描述符来描述。read函数作用:
从文件描述符 fd 中读 count 个字节 进入 buf区。函数执行成功返回读入的字节数,失败的话返回 -1, 并
对 errno 赋予相应的值。
3.ssize_t write(int fd, const void *buf, size_t count);
和 read 函数相反,从 buf 里写count个字节进入文件描述符fd里面。
4.off_t lseek(int fildes, off_t offset, int whence);
off_t : file sizes and offsets(signed);
lseek是随机访问文件函数。这个函数非常重要。因为每次对文件进行读写操作的位置总是在前一次操作之后。
这样有时候要访问文件的其他位置就麻烦了,就得依靠这个函数了。
fildes:文件描述符;
offset:访问的文件的位置
whence:值可以是0,1,2;分别表示从文件开始、从文件当前位置、从文件结束位置;
返回值:成功就返回新的文件位置,失败返回-1。
5. int close(int fd);
close 很简单,关闭一个文件描述符,这样就这个文件内容就不会被无意修改和使用了。
返回0表示执行成功,返回-1表示执行失败。
6. int creat(const char *pathname, mode_t mode);
用于创建一个新的文件。参数就不说了,参照open函数。 creat函数返回一个新文件描述符。
三、实例简单分析:
实例1:下面的程序是来自Figure 3.2,利用几个基本函数构造而成,非常简单,简单的分析都在注释里面
了;
#include "apue.h"
#include fcntl.h>
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
int main(void)
{
int fd;
/*offset is 0 when the file is created.*/
if ((fd = creat("file.hole", FILE_MODE)) 0)
err_sys("creat error!");
/*offset is 10 after calling the write function.
* write 10 bytes form buf1 to fd*/
if (write(fd, buf1, 10) != 10)
err_sys("buf1 write error!");
/*offset is 16384 after calling the lseek function*/
if (lseek(fd, 16384, SEEK_SET) == -1)
err_sys("lseek error!");
/*offset is 16394 because we write 10 bytes form buf2*/
if (write(fd, buf2, 10) != 10)
err_sys("write error!");
exit (0);
}
实例2 :read & write 的配合
#include "apue.h"
int main(void)
{
int n;
char buf[4096];
/*read from the stdin file and write to stdout*/
while ((n = read(STDIN_FILENO, buf, 4096)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n 0)
err_sys("read error");
exit (0);
}
四、后记
其实第3章我没全学完,这只是对一部分的学习笔记,等后面的内容学习后再补充上去。由于刚学,
难免写得比较肤浅,而且写这篇文章时间比较紧,可能还有一些认识上的错误,请师傅还有其他一些朋友指
教!
lj_860603(键键)
2006.12.13
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/27541/showart_214877.html |
|