为什么调用dup2会出错?
Why does the calling of dup2 go wrong?
如你所见,程序有两个文件指针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;
}
正如评论已经提到的,您不应该将文件操作与流(使用 FILE*
、fopen
、fwrite
、fclose
)与原始文件操作混合(使用文件描述符,open
、write
、close
、dup2
)。尤其不要像您在这段代码中那样将它们混合在同一个文件中 pointer/descriptor。
让我们浏览一下代码,看看它为什么会这样:
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);
这会刷新缓冲区,因此实际写入磁盘的操作发生在此处。因为描述符已更改,如果直到现在都没有刷新,两个流实际上将刷新到磁盘上的同一个文件。
这可能就是您看到该行为的原因,但请记住,您所做的并不安全,行为或文件内容可能有所不同。
如你所见,程序有两个文件指针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;
}
正如评论已经提到的,您不应该将文件操作与流(使用 FILE*
、fopen
、fwrite
、fclose
)与原始文件操作混合(使用文件描述符,open
、write
、close
、dup2
)。尤其不要像您在这段代码中那样将它们混合在同一个文件中 pointer/descriptor。
让我们浏览一下代码,看看它为什么会这样:
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);
这会刷新缓冲区,因此实际写入磁盘的操作发生在此处。因为描述符已更改,如果直到现在都没有刷新,两个流实际上将刷新到磁盘上的同一个文件。
这可能就是您看到该行为的原因,但请记住,您所做的并不安全,行为或文件内容可能有所不同。