管道、FIFO以及某些设备,特别是终端、网络和STREAMS设备有下列两种性质:

(1)一次read操作所返回的数据可能少于所要求的数据,即使还没有达到文件尾端也可能是这样。这不是一个错误,应当继续读该设备。

(2)一次write操作的返回值也可能少于指定输出的字节数。这可能是由若干因素造成的,例如,下游模块的流量控制限制。这也不是错误,应当继续写余下的数据至该设备。(通常,只有对非阻塞描述符,或捕捉到一个信号时,才发生这种write的中途返回。)

在读、写磁盘文件时从未见到过这种情况,除非文件系统用完了空间,或者我们接近了配额限制,而不能将要求写的数据全部写出。

通常当读、写一个管道、网络设备或终端时,我们需要考虑这些特性。下面两个函数readn和writen的功能是读、写指定的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(通常只调用read接收来自这些设备的数据)。

程序清单14-11包含了writen和readn的一种实现。

程序清单14-11 readn和writen函数

#include "apue.h"

size_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 amount written so far */
}
else if (nwritten == 0)
{
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft); /* return >= 0 */
}

注意,若在已经读、写了一些数据后出错,则这两个函数返回已经传输的数据量,而非出错返回。与此类似,在读时如达到文件尾,而且在此之前已经成功地读了一些数据,但尚未满足所要求的量,则readn返回已复制到调用者缓冲区中的字节数。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

高级I/O之readn和writen函数的更多相关文章

  1. Linux网络编程-readn函数、writen函数、readline函数实现

    readn函数功能:在网络编程的读取数据中,通常会需要用到一个读指定字节才返回的函数,linux系统调用中没有给出,需要自己封装. readn实现代码: int readn(int fd, void ...

  2. 网络编程readn、writen和readline函数的编写

    readn   在Linux中,read的声明为: ssize_t read(int fd, void *buf, size_t count); 它的返回值有以下情形: 1.大于0,代表成功读取的字节 ...

  3. 【读书笔记】读《JavaScript高级程序设计-第2版》 - 非函数部分

    章节列表: 第08章:BOM 第09章:客户端检测 第10章:DOM 第11章:DOM2和DOM3 第12章:事件 第13章:表单脚本 第14章:错误处理与调试 第17章:Ajax和JSON第20章: ...

  4. 高级I/O之readv和writev函数

    readv和writev函数用于在一次函数调用中读.写多个非连续缓冲区.有时也将这两个函数称为散布读(scatter read)和聚集写(gather write). #include <sys ...

  5. JavaScript高级程序设计(读书笔记)之函数表达式

    定义函数的方式有两种:一种是函数声明,另一种就是函数表达式. 函数声明的一个重要特征就是函数声明提升(function declaration hoisting),意思是在执行代码前会先读取函数声明. ...

  6. 【Unix环境高级编程】编写变长参数函数

    文件的格式输入输出函数都支持变长参数.定义时,变长参数列表通过省略号'...'表示, 因此函数定义格式为: type 函数名(parm1, parm2,parmN,...); Unix的变长参数通过v ...

  7. 《Javascript高级程序设计》读书笔记之bind函数详解

    为什么需要bind var name = "The Window"; var object = { name: "My Object", getNameFunc ...

  8. Oracle 高级查询、事物、过程及函数

    一.Sql函数 1.数值函数(输入参数和返回值都是数值型,多数函数精确到38位) --多少次方 ,) from dual; --开方 ) from dual; --绝对值 ) from dual; - ...

  9. UNIX环境高级编程——信号基本概述和signal函数

    一.为了理解信号,先从我们最熟悉的场景说起:1. 用户输入命令,在Shell下启动一个前台进程.2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断.3. 如果CPU当前正在执行这个进程的代码,则 ...

随机推荐

  1. codeforces 691D Swaps in Permutation DFS

    这个题刚开始我以为是每个交换只能用一次,然后一共m次操作 结果这个题的意思是操作数目不限,每个交换也可以无限次 所以可以交换的两个位置连边,只要两个位置连通,就可以呼唤 然后连通块内排序就好了 #in ...

  2. XCode修改工程名注意

    以下文字转载过来,在使用的过程中遇到几个问题 1.需要在 Build phases 里面,检查下 Link Binary With Libraries 以及Compline Sources 2.Bul ...

  3. 欧拉图 CCF2016第六次 送货

    // 欧拉图 CCF2016第六次 送货 // 思路: // CCF数据很水....这道题有问题 // 先判连通,再dfs边. // 应为输出要满足字典序最小,用vector存图,sort一遍,用st ...

  4. C#实现APK自动打包

    C#实现APK自动打包     最近做了一个安卓项目,其中有一个自动打包的功能,要把供应商id写入APK后打包.   一.思路     在AndroidMinifest.xml中加入一个标识字段,如下 ...

  5. HBase Shell手动移动Region

    在生产环境中很有可能有那么几个Region比较大,但是都运行在同一个Regionserver中. 这个时候就需要手动将region移动到负载低的Regionserver中. 步骤: 1.找到要移动的r ...

  6. list、tuple、dict、set、map

    list Python内置的一种数据类型是列表. list是一种有序的集合,可以随时添加和删除其中的元素. # 创建list classmate = ['micheal', 'Bob', 'Tracy ...

  7. linux内核书籍

    1, 关于操作系统理论的最初级的知识.不需要通读并理解<操作系统概念><现代操作系统>等巨著,但总要知道分时(time-shared)和实时(real-time)的区别是什么, ...

  8. Git Book 中文版 - Git的撤消操作 - 重置, 签出 和 撤消

    Git Book 中文版 - Git的撤消操作 - 重置, 签出 和 撤消 Git的撤消操作 - 重置, 签出 和 撤消 Git提供了多种修复你开发过程中的错误的方法. 方法的选择取决于你的情况: 包 ...

  9. 第三百天了 how can I 坚持

    郭娜还是不搭理我,或许是真没有遇到合适的.? 该咋办,好焦虑. 其实态度应该放低点,就这样是找不到对象的. 有必要这么死耗嘛,人生总是这么纠结. 周六年后,周日来吃火锅,这一年又过去了. 睡觉.

  10. STL学习系列五:Queue容器

    Queue简介 queue是队列容器,是一种“先进先出”的容器. queue是简单地装饰deque容器而成为另外的一种容器. #include <queue> 1.queue对象的默认构造 ...