重定向后stdout流改变顺序?

时间:2015-08-13 14:18:32

标签: c io-redirection

这些天我正在学习" apue",一个典型案例的结果使我感到困惑。以下是" sample.c"的示例代码:

#include "apue.h"
#include <stdio.h>
#define BUFF_SZ 4096

int main()
{
    int n = 0;
    char buff[BUFF_SZ] = {'\0'};
    while ((n = read(STDIN_FILENO, buff, BUFF_SZ)) > 0) {
        printf("read %d bytes\n", n);
        if (write(STDOUT_FILENO, buff, n) != n) {
            err_sys("write error");
        }
    }
    if (n < 0) {
        err_sys("read error");
    }
    return 0;
}

编译gcc sample.c后,您可以使用此命令echo Hello | ./a.out并在终端上获得以下标准输出:

  

读取6个字节
你好

但是,如果输出重定向到文件echo Hello | ./a.out > outfile,请使用cat outfile查看内容:

  

你好,读取6个字节

重定向之后,输出会更改顺序!我想知道是否有人可以告诉我原因?

3 个答案:

答案 0 :(得分:4)

对于标准I / O函数var throttledFunctions = {}; ["name", "email"].forEach(function (fieldName) { throttledFunctions[fieldName] = _.throttle(function (context, event) { Meteor.call("updateForm", context._id, event.target.name, event.target.value, ...) }, 1000); }); Template.TheForm.events({ "input #TheForm .field": function (event) { throttledFunctions[event.target.name](this, event); } }); ,当您输出到终端时,标准输出默认为行缓冲。

printf

printf("read %d bytes\n", n); 这里导致输出刷新。

但是,当您输出到文件时,它默认是完全缓冲的。除非缓冲区已满,否则输出将不会刷新,或者您明确刷新它。

另一方面,低级系统调用\n是无缓冲的。

通常,不建议将标准I / O调用与系统调用混合使用。

答案 1 :(得分:2)

默认情况下,

printf()缓冲其输出,而write()则不缓冲,并且之间没有同步。

因此,在您的代码中,printf()可能会将其数据存储在缓冲区中并返回,然后调用write(),并且 - main()返回时,{{1}刷新缓冲区以便显示缓冲输出。根据您的描述,在重定向输出时会发生这种情况。

printf()也可能立即写入数据,然后调用printf()。根据您的描述,当输出未被重定向时会发生这种情况。

通常,流的重定向的一部分正在改变缓冲区 - 因此缓冲时的行为 - 用于write()stdout等流。精确的更改取决于发生的重定向类型(例如,文件,管道,不同的显示设备等)。

想象一下,stdin将数据写入缓冲区,并在刷新缓冲区时使用printf()生成输出。这意味着write()的所有公开调用都会立即生成其输出,但缓冲的数据可能会无序打印。

答案 2 :(得分:0)

问题在于写入是由write(2)调用处理的,因此您实际上无法控制所发生的事情。 如果我们查看write(2)的文档,我们可以看到在read()发生之前不能保证写入实际写入。更具体地说:

A successful return from write() does not make any guarantee that data has 
been committed to disk. In fact, on some buggy implementations, it does not even 
guarantee that space has successfully been reserved for the data. The only way to 
be sure is to call fsync(2) after you are done writing all your data. 

这意味着根据write(2)的实现和缓冲(即使重定向和打印到屏幕之间可能不同),您也可以得到不同的结果。