The C Programming Language(第 2 版) 笔记 / 8 UNIX 系统接口 / 8.2 低级 I/O(read 和 write)

目录、参考文献


8.2 低级 I/O(read 和 write)

输入与输出是通过 readwrite 系统调用实现的
在 C 语言程序中,可以通过函数 readwrite 访问这两个系统调用
这两个函数中,第一个参数是文件描述符,第二个参数是程序中存放读或写的数据的字符数组,第三个参数是要传输的字节数

int n_read = read(int fd, char *buf, int n); 
int n_written = write(int fd, char *buf, int n);

每个调用返回实际传输的字节数
在读文件时,函数的返回值可能会小于请求的字节数
如果返回值为 0,则表示已到达文件的结尾,如果返回值为 -1,则表示发生了某种错误
在写文件时,返回值是实际写入的字节数
如果返回值与请求写入的字节数不相等,则说明发生了错误

在一次调用中,读出或写入的数据的字节数可以为任意大小
最常用的值为 1,即每次读出或写入 1 个字符(无缓冲),或是类似于 1024 ~ 4096 这样的与外围设备的物理块大小相应的值
用更大的值调用该函数可以获得更高的效率,因为系统调用的次数减少了

结合以上的讨论,我们可以编写一个简单的程序,将输入复制到输出,这与第 1 章中的复制程序在功能上相同
程序可以将任意输入复制到任意输出,因为输入/输出可以重定向到任何文件或设备

#include "syscalls.h"

main() /* copy input to output */ 
{ 
    char buf[BUFSIZ]; 
    int n;
    
    while ((n = read(0, buf, BUFSIZ)) > 0) 
        write(1, buf, n); 
    return 0; 
}

我们已经将系统调用的函数原型集中放在一个头文件 syscalls.h
因此,本章中的程序都将包含该头文件,不过,该文件的名字不是标准的

参数 BUFSIZ 也已经在 syscalls.h 头文件中定义
对于所使用的操作系统来说,该值是一个较合适的数值
如果文件大小不是 BUFSIZ 的倍数,则对 read 的某次调用会返回一个较小的字节数
write 再按这个字节数写,此后再调用 read 将返回 0

为了更好地掌握有关概念,下面来说明如何用 readwrite 构造类似于 getcharputchar 等的高级函数
例如,以下是 getchar 函数的一个版本,它通过每次从标准输入读入一个字符来实现无缓冲输入

#include "syscalls.h"

/* getchar: unbuffered single character input */ 
int getchar(void) 
{
    char c; 
    return (read(0, &c, 1) == 1) ? (unsigned char) c : EOF; 
}

其中,c 必须是一个 char 类型的变量,因为 read 函数需要一个字符指针类型的参数(&c
在返回语句中将 c 转换为 unsigned char 类型可以消除符号扩展问题

getchar 的第二个版本一次读入一组字符,但每次只输出一个字符

#include "syscalls.h"

/* getchar: simple buffered version */ 
int getchar(void) 
{ 
    static char buf[BUFSIZ]; 
    static char *bufp = buf; 
    static int n = 0;
    
    if (n == 0) { /* buffer is empty */ 
        n = read(0, buf, sizeof buf); 
        bufp = buf; 
    } 
    return (--n >= 0) ? (unsigned char) *bufp++ : EOF; 
}

如果要在包含头文件 <stdio.h> 的情况下编译这些版本的 getchar 函数
就有必要用 #undef 预处理指令取消名字 getchar 的宏定义,因为在头文件中,getchar 是以宏方式实现的


目录、参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值