03 读书笔记:第1章 UNIX基础知识 (2)

1 文件描述符

       文件描述:简单的讲,就是一个文件的标识(ID)。内核用文件描述符标识一个特定进程正在访问的文件。当内核打开一个已有文件或创建一个新文件时,它返回一个文件描述符。在读写文件时,就可使用它。每当运行一个新程序时,所有的shell都为其打开三个文件描述符:标准输入、标准输出、标准出错。

2 不带缓冲区的I/O

        函数open、read、write、lseek以及close提供了不用缓冲的I/O。这些函数都使用文件描述符。

        《UNIX环境高级编程》P6:程序清单1-2  将标准输入复制到标准输出(有改动)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define BUFFSIZE 4096

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

    while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)    // 从标准输入读取数据,并将数据保存到buf缓冲区中,返回值为读取到的字节数
        if (write(STDOUT_FILENO, buf, n) != n) {           // 将buf缓冲区中的数据写入到标准输出,返回值为写入到标准输出的字节数
            fprintf(stderr, "write error\n");
        }

    exit(0);
}

        两个常量STDIN_FILENO和STDOUT_FILENO在<unistd.h>中定义,它们指定了标准输入和标准输出的文件描述符,典型的值为0和1。

        read函数返回读到的字节数,当到达文件结尾时(按键为Ctrl+D),read返回0;如果读取出错,read返回-1。使用不同的BUFFSIZE会影响程序的效率。

3 标准I/O

        标准IO函数提供一种对不用缓冲I/O函数的带缓冲的接口。<stdio.h>包括了所有标准I/O函数的原型。

        优点:

                使用标准I/O函数可以无需担心如何选取最佳的缓冲区大小;

                简化了对输入行的处理。如fgets()函数读取完整的一行。

        《UNIX环境高级编程》P7:程序清单1-3  用标准I/O将标准输入复制到标准输出(有改动)

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int c;

    while ((c = getc(stdin)) != EOF)            // 从标准输入读取一个字符
        if (fputc(c, stdout) == EOF)            // 向标准输出写入一个字符
            fprintf(stderr, "output error\n");
    if (ferror(stdin))
        fprintf(stderr, "input error");

    exit(0);
}

        标准输入/输出常量stdin和stdout在头文件<stdio.h>中定义,它们分别表示标准输入和标准输出文件。(而不用缓冲区I/O的常量为STDIN_FILENO和STDOUT_FILENO,在<unistd.h>中定义

PS:

        感觉文件描述符、套接字、进程都是用同样的方法来标识相应的对象。

        不用缓冲区的I/O和标准I/O感觉有点迷糊。根据我的理解,应该如下图所示:

                   03 读书笔记:第1章 UNIX基础知识 (2)

        从图中可以看出,用户使用标准I/O读取数据时存在延迟,因为程序是从标准I/O的缓冲区中读取数据。是否使用缓冲区对网络编程影响很大,一不小心会出现BUG,《UNIX网络编程》卷1中有详细的说明。


你可能感兴趣的:(读书笔记,《UNIX环境高级编程》)