dup()和缓存刷新

时间:2014-11-03 13:20:37

标签: c flush dup

我是C初学者,尝试使用dup(),我编写了一个程序来测试这个函数,结果与我的预期略有不同。

代码

// unistd.h, dup() test

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

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);
    FILE *f_dup = fdopen(fd_dup, "w+");

    // write to file, use the duplicated file descriptor,
    fputs("hello\n", f_dup);
    fflush(f_dup);
    // close duplicated file descriptor,
    fclose(f_dup);
    close(fd_dup);

    // allocate memory
    int maxSize = 1024; // 1 kb
    char *buf = malloc(maxSize);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, maxSize, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}

程序尝试通过复制的fd写入,然后关闭复制的fd,然后尝试通过原始的fd读取。

我预计当我关闭重复的fd时,io缓存会自动刷新,但事实并非如此,如果我删除代码中的fflush()函数,原来的fd将无法读取由已经关闭的重复fd写的内容。

我的问题是

这是否意味着当关闭重复的fd时,它不会自动刷新?


@Edit:

对不起,我的错误,我找到了原因,在我的初步计划中:

close(fd_dup);

但没有:

fclose(f_dup);

使用fclose(f_dup);替换close(f_dup);后,它可以正常工作。

因此,如果以适当的方式关闭,重复的fd会自动刷新write()&amp; close()是一对,fwrite()&amp; fclose()是一对,不应混用它们。

实际上,在代码中我可以直接使用重复的fd_dup与write()&amp; close(),并且根本无需创建新的FILE

因此,代码可能只是:

// unistd.h, dup() test

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

#define BUF_SIZE 1024 // 1 kb

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);

    // write to file, use the duplicated file descriptor,
    write(fd_dup, "hello\n", BUF_SIZE);
    // close duplicated file descriptor,
    close(fd_dup);

    // allocate memory
    char *buf = malloc(BUF_SIZE);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, BUF_SIZE, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}

2 个答案:

答案 0 :(得分:2)

来自dup手册页:

  

从这些系统调用之一成功返回后,旧文件描述符和新文件描述符可以互换使用。它们引用相同的打开文件描述(参见open(2)),从而共享文件偏移量和文件状态标志;例如,如果通过在其中一个描述符上使用lseek(2)修改文件偏移量,则另一个描述符的偏移量也会更改。

这意味着当您写入重复的文件描述符时会更改搜索指针,因此,在写入复制后从第一个文件描述符读取不应读取任何数据。

您正在使用fdopen创建重复流的分离的seek_ptr和end_ptr,这样,fd_dup就会停止重复。这就是为什么你可以在刷新和关闭流后读取数据。

如果你不刷新第二个文件描述符,我找不到任何有关你无法阅读的强有力的事实。我可以补充一点,它可能与sync系统调用有关。

毕竟,如果你需要一个IO缓冲区,你可能会使用错误的机制,检查命名管道和其他缓冲操作系统机制。

答案 1 :(得分:1)

我无法理解你的问题。我在Microsoft VC2008下测试了它(必须用io.h替换unistd.h)和gcc 4.2.1。

我注释掉了fflush(f_dup),因为它在关闭之前没有用close(fd_dup);,因为文件描述符已经关闭了,所以这段代码现在看起来像:

// write to file, use the duplicated file descriptor,
fputs("hello\n", f_dup);
// fflush(f_dup);
// close duplicated file descriptor,
fclose(f_dup);
// close(fd_dup);

它运作正常。我上了两个系统:

original file descriptor:       3
duplicated file descriptor:     4
hello