APUE 学习记录 20200628

3.7 函数read

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

#include 
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 
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字节的结果如下:
APUE 学习记录 20200628_第1张图片

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

你可能感兴趣的:(linux编程)