为什么调用dup2会出错?

时间:2015-03-23 23:50:50

标签: c io

如您所见,该程序有两个文件指针sport和fruit指向文件fruit.txt。问题是运行程序后,sport.txt为空,fruit.txt包含中文字符。我期望sport.txt应该包含单词“basketball”,因为它在重定向发生之前写入文件。那么,这里有什么问题?

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "../cus_header/cus_header.h"

int main(){

    FILE *fruit = fopen("fruit.txt", "w");
    if(!fruit)
        error("cannot open fruit.txt");

    FILE *sport = fopen("sport.txt", "w");
    if(!sport)
        error("cannot open sport.txt");

    int de_sport = fileno(sport);
    int de_fruit = fileno(fruit);

    printf("file number of sport.txt: %i and of fruit.txt: %i\n", de_sport, de_fruit);

    fwrite("basketball", sizeof(char), 10, sport);

    fwrite("apple", sizeof(char), 6, fruit);

    if(dup2(de_fruit, de_sport) == -1)
        error("cannot redirect");

    fwrite("basketball", sizeof(char), 10, sport); //???
    fwrite("apple", sizeof(char), 6, fruit); // ???

    fclose(sport);
    fclose(fruit);

    return 0;
}

1 个答案:

答案 0 :(得分:0)

正如评论已经提到的那样,您不应该将文件操作与流(使用FILE*fopenfwritefclose)混合使用原始文件操作(使用文件描述符,openwriteclosedup2)。特别是不要像在这段代码中那样将它们混合在同一个文件指针/描述符上。

让我们浏览一下代码,了解它的行为方式:

FILE *fruit = fopen("fruit.txt", "w");
...
FILE *sport = fopen("sport.txt", "w");

你不应该关心FILE结构的外观,让我们假设它将底层文件描述符放在某处。

int de_sport = fileno(sport);
int de_fruit = fileno(fruit);

您创建的局部变量包含与两个FILE*引用相同的文件描述符。

fwrite("basketball", sizeof(char), 10, sport);
fwrite("apple", sizeof(char), 6, fruit);

你在两个文件中都写了些东西。由于默认情况下C文件流是缓冲的,因此磁盘上文件中的实际写入可能不会立即发生(在您的情况下它不会发生)。

dup2(de_fruit, de_sport)

这会关闭文件描述符de_sport并使其引用与de_fruit相同的文件。实际数值保持不变,只更改它们引用的实际文件。这意味着在FILE调用后,两个dup2句柄将写入同一文件。

fwrite("basketball", sizeof(char), 10, sport); //???
fwrite("apple", sizeof(char), 6, fruit); // ???

这将写入相同的底层文件,因为这两个描述符现在引用同一个文件。但同样,因为流被缓冲,实际上这可能只是附加到这两个FILE*的缓冲区。

fclose(sport);
fclose(fruit);

这会刷新缓冲区,因此实际写入磁盘就在这里。因为描述符已被更改,如果直到现在都没有发生刷新,则两个流实际上将刷新到磁盘上的同一文件。

这可能就是您看到这种行为的原因,但请记住,您所做的事情并不安全,行为或文件内容可能会有所不同。