管道、FIFO和一些设备,尤其是终端、网络和STREAMS设备,有以下两个属性。
1、一个read操作可能返回比请求更少,即使我们没有遇到文件尾。这不是一个错误,我们应该简单地继续从设备读。
2、一个write操作也可能返回比我们指定的少。例如它可能因为向下的流模块的控制流限制。再次,这不是一个错误,我们应该继续写剩余的数据。(通常,这从一个write而来的短返回只在非阻塞描述符或如果一个信号被捕获是发生。)
我们将不会在读写磁盘文件时看到这个发生,除了发文件系统没有空间,或我们达到了配额限制而我们不能全部写完我们请求的。
一般说来,当我们读或写一个管道、网络设备或终端时,我们需要考虑这些特性。我们可以使用以下两个函数来读写N字节的数据,让这些函数处理一个可能的比请求小的值。这两个函数简单地调用read或write,尽可能多次地来读写整个N字节的数据。
- #include "apue.h" /* 自己写的函数 */
- ssize_t readn(int filedes, void *buf, size_t nbytes);
- ssize_t writen(int filedes, void *buf, size_t nbytes);
- 两者返回读或写的字节数,错误返回-1。
我们定义这些函数,作为以后例子的便利工具,和本文许多例子里使用的错误处理例程一样。readn和writen函数不是任何标准的一部分。
我们调用writen,每当我们向某个我们提到的文件类型写时,但是我们只在我们提前知道我们将收到特定字节数量时才调用readn。下面的代码展示了readn和writen的实现,我们将在后面的例子里使用它们。
- #include <fcntl.h>
- ssize_t /* Read "n" bytes from a descriptor */
- readn(int fd, void *ptr, size_t n)
- {
- size_t nleft;
- ssize_t nread;
- nleft = n;
- while (nleft > 0) {
- if ((nread = read(fd, ptr, nleft)) < 0) {
- if (nleft == n)
- return(-1); /* error, return -1 */
- else
- break; /* error, return amount read so far */
- } else if (nread == 0) {
- break; /* EOF */
- }
- nleft -= nread;
- ptr += nread;
- }
- return(n - nleft); /* return >= 0 */
- }
- ssize_t /* Write "n" bytes to a descriptor */
- writen(int fd, const void *ptr, size_t n)
- {
- size_t nleft;
- ssize_t nwritten;
- nleft = n;
- while (nleft > 0) {
- if ((nwritten = write(fd, ptr, nleft)) < 0) {
- if (nleft == n)
- return(-1); /* error, return -1 */
- else
- break; /* error, return amout written so far */
- } else if (nwritten == 0) {
- break;
- }
- nleft -= nwritten;
- ptr += nwritten;
- }
- return(n - nleft); /* return >= 0 */
- }
注意如果我们碰到一个错误而之前读过或写过任何数据,那么我们返回已经传输的数据而不是错误。相似地,如果我们在读时到达文件尾,我们返回拷贝到调用者缓冲的字节数,如果我们已经成功读了一些数据,但并没有满足请求的量。
阅读(467) | 评论(0) | 转发(0) |