APUE-学习记录-20200628

37次阅读

共计 1588 个字符,预计需要花费 4 分钟才能阅读完成。

3.7 函数 read

调用 read 函数从打开文件中读数据。

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes); // 返回值:读到的字节数,若已到文件尾,返回 0;若出错,返回 -1

如 read 成功,则返回读到的字节数。如已到达文件的尾端,则返回 0.
有多种情况可使实际读到的字节数少于要求读的字节数:

  • 读普通文件时,在读要求字节数之前已到达了文件尾端。
  • 当从终端设备读时,通常一次最多读一行。
  • 当从网络读时,网络中的缓冲机制可能造成但绘制小于所要求读的字节数。
  • 当从管道或 FIFO 读时,如若管道包含的字节少于所需的数量,那么 read 将只返回实际可用的字节数。
  • 当从某些面向记录的设备(如磁带)读时,一次最多返回一个记录。
  • 当一信号造成中断,而已经读了部分数据量时。

读操作从文件的当前偏移量处开始,在成功返回之前,该偏移量将增加实际读到的字节数。

POSIX.1 从几个方面对 read 函数的原型做了更改。经典的原型定义是:

int read(int fd, char *buf, unsigned nbytes);
  • 首先,为了与 ISO C 一致,第二个参数由 char * 改为 void *。在 ISO C 中,类型 void * 用于便是通用指针。
  • 其次,返回值必须是一个带符号整型(ssize_t),以保证能够返回正整数字节数、0 或 -1。
  • 最后,第三个参数在历史上是一个无符号整型,这允许一个 16 位的实现一次读或写的数据可以多达 65534 个字节。

3.8 函数 write

调用 write 函数向打开文件中写数据。

#include <unistd.h>
ssize_t write(int fd, void * buf, size_t nbytes); // 返回值:若成功,返回已写的字节数;若出错,返回 -1

其返回值通常与参数 nbytes 值相同,否则表示出错。write 出错的一个常见原因是磁盘已写满,或者超过了一个给定进程的文件长度限制。

对于普通文件,写操作从文件的当前偏移量处开始。如果在打开文件时,制定了 O_APPEND 选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数。

3.9 I/ O 的效率

Page 58 示例:只使用 read 和 write 函数复制一个文件。

#include "apue.h"

#define BUFFSIZE 4096

int main(void)
{
    int n;
    char buf[BUFFSIZE];

    while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
        if(write(STDOUT_FILENO, buf, n) != n)
            err_sys("write error");

    if(n < 0)
        err_sys("read error");

    exit(0);
}

关于该程序应注意以下几点:

  • 它从编撰输入读,写至标准输出,这就假定在执行本程序之前,这些标准输入、输出已由 shell 安排好。
  • 考虑到进程终止时,UNIX 系统内核会关闭进程的所有打开的文件描述符,所以此程序并不关闭输入和输出文件。
  • 对 UNIX 系统而言,文本文件和二进制代码文件并无区别,所以本程序对这两种文件都有效。

我们还没有回答的一个问题是如何选取 BUFFSIZE 值。使用本程序在 ext4 文件系统上(磁盘块长度为 4096 字节),读 516581760 字节的结果如下:

CPU 时间最小值出现在 4096 及以后的位置,继续增加缓冲区长度对此时间机会没有影响。
大多数文件系统为改善性能都采用某种预读技术,当检测到正进行顺序读取时,系统就试图读入比应用所要求的更多数据,并假象应用很快就会读这些数据。

3.10 文件共享

UNIX 系统支持在不同进程见共享打开文件。在介绍 dup 函数之前,先要说明这种共享。

内核使用 3 种数据结构表示打开文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能的影响。

正文完
 0