[UNIX系统编程] I/O缓冲

使用缓冲的目的当然就是为了提高性能了。在UNIX中,I/O 有两层缓冲:
1. 内核缓冲
2. stdio 库缓冲

内核缓冲:
当使用系统调用write的时候,并不是直接写入磁盘,这样性能太挫。而是先写到内核缓冲区,等缓冲区满了,或者调用sync的时候,才写入磁盘。经过实验,我们发现当缓冲区大小为4096个字节时,性能几乎达到最优,于是乎就用这个值了。

stdio 库缓冲:
当使用printf及其同类的时候,并不相当于调用了write,而是在用户空间中开辟了一块 stdio 缓冲区,先写到这里。为什么又要加一层缓冲呢?试想,如果用户反复地调用write,那么就会产生大量的系统调用。系统调用虽然很快,但是多了的话开销还是很大的咧!为了减少系统调用带来的开销,于是有了 stdio 库缓冲。

混合使用:
试编译如下代码:

printf("If I have more time, \n");
write (STDOUT_FILENO, "I would have written you a shorter letter.\n", 43);

如果执行./a.out,输出如下:

If I have more time,
I would have written you a shorter letter.

如果执行./a.out > outfile,outfile 如下:

I would have written you a shorter letter.
If I have more time,

其实第二种情况反而比较好理解,因为write直接写到内核缓冲,而printf先写到stdio缓冲,然后再写到内核缓冲,所以输出就慢了。
而第一种情况为什么又是按顺序的呢?其实是因为'\n'。如果把'\n'去掉,输出就跟outfile一样了。原因是,如果输出到终端,且含有'\n',就会直接flush掉,不会缓冲。

练习:
了解了UNIX的缓冲机制,来一道小题联系联系:实现tail -n功能(使用 lseek, read, write 等实现)。
实现如下所示,

#include "tlpi_hdr.h"
#include <fcntl.h>

#define MAX_BUF_SIZE 4096

int main(int argc, char const *argv[])
{
    int fd;
    int lineNum = 10;
    off_t offset;
    int read_size;
    int numRead;
    char buf[MAX_BUF_SIZE];
    int ch;

    /*Get option: [-n num]*/
    while ((ch = getopt(argc, argv, "n:")) != -1) {
        switch (ch) {
            case 'n':
                lineNum = atoi(optarg);
                break;

            case '?':
            default:
                printf("Usage: ./tail [-n num] [file]\n");
                exit(EXIT_FAILURE);
        }
    }
    argc -= optind;
    argv += optind;

    /* Open file. */
    fd = open(argv[0], O_RDONLY);
    if (fd == -1)
        errExit("open");

    /* Seek to end and read backward. */
    offset = lseek (fd, 0, SEEK_END);
    while (offset > 0) {
        /* Seek backward. */
        read_size = min (offset, MAX_BUF_SIZE);
        offset = lseek (fd, -read_size, SEEK_CUR);
        if (offset == -1)
            errExit("lseek");

        /* pread will not change the offset. */
        numRead = pread (fd, buf, read_size, offset);
        if (numRead == -1)
            errExit("pread");

        /* Count how many lines in buf. */
        if (buf[numRead - 1] == '\n')  // Some files are not end of '\n'.
            numRead--;
        for (; numRead > 0; numRead--) {
            if (buf[numRead - 1] == '\n') lineNum--;
            if (lineNum <= 0) break;
        }

        if (numRead > 0) {
            offset = lseek (fd, numRead, SEEK_CUR);
            if (offset == -1)
                errExit ("lseek");
            break;
        }
    }

    /* print all the last n lines.*/
    while ((numRead = read(fd, buf, MAX_BUF_SIZE)) > 0) {
        if (write(STDOUT_FILENO, buf, numRead) == -1)
            errExit("write");
    }

    close(fd);
    exit (0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值