11-11 重定向标准输入输出流(部分待定)

1. freopen() 将 stdout 重定向到其他文件流

        stdout 是输入到控制台中的文件流,但可以通过 freopen() 函数将其重定向到其他文件流,即输出内容不再显示在控制台,而在指定文件流(例如自定义的文件)中。例如,将 stdout 原本输出到控制台的内容输出到 output.txt 文件中。

void TestFreopen(){

  // attention: Chinese cannot be written here!
  freopen("output.txt", "a", stdout); // 将 stdout 文件流重定向到 output.log 文件中

  puts("hello world");
  fclose(stdout);
}

        freopen() 函数的缺陷在于可以将 stdout 重定向到其他文件流中,但无法将 stdout 恢复至原有文件流。即可以将 stdout 由控制台输出变换到文件输出,但不能将 stdout 由文件输出恢复到控制台输出,重定向过程不可逆。原因在于 freopen() 的第一个参数为文件名,而不是文件流。

2. dup(),dup2() 将 stdout 重定向到其他文件流

        为了将重定向过程可逆,即 stdout 可以重定向到其他文件流,也可从其他文件流重定向到原有的 stdout,使用 dup() 和 dup2() 函数

        dup() 函数可以复制一个文件的文件描述符,如下图所示。定义一个 fd1,将 fd0 的文件描述符赋值给 fd1。

        dup2() 函数的操作对象是两个文件描述符,可将 fd1 的文件描述符指向 fd0 文件描述符指向的文件。

         此外,可利用 fileno() 函数获取文件流的文件描述符close() 函数功能为关闭文件描述符

        每个文件流对应一个文件描述符,每个文件描述符对应一个文件。所以,stdout 文件流对应一个控制台输出文件 stdout_A,其他文件流(一个的情况下)也对应一个文件 file_B。利用 freopen() 函数可将 stdout 文件流对应的文件从 stdout_A 转换为 file_B,而利用 dup2() 函数可将 stdout 对应的 file_B 文件重新转化为 stdout_A。这其中利用的便是文件描述符,修改 stdout 的文件描述符,让其重新指向 stdout_A 文件。

// dup() 函数在不同系统下的头文件名
#if defined(__APPLE__) || defined(__linux__)
# include <unistd.h>
#elif defined(_WIN32)
# include <io.h>
#endif


// 1. 是否要转化为文件流
// 2. 转化之前是否是控制台输出的文件流
void TestDup(char const* filename){

  static int save_stdout_no = -1;  // 定义一个文件描述符,-1 为控制台输出

  if(filename){  // 将 stdout 重定向至 其他文件流

    if(save_stdout_no == -1){  // 如果此时为控制台输出
      // 保存 stdout 控制台输出的文件描述符
      save_stdout_no = dup(fileno(stdout));
    }

    fflush(stdout);  // 将控制台缓存全部清除
    freopen(filename, "a", stdout); // 文件流之间的相互转化可借助文件名进行,stdout没有对应文件名,所以麻烦了点

  }else{ // 如果文件名为 NULL,说明想恢复至原有的 stdout 文件流

    if(save_stdout_no != -1){  // 不在控制台输出,需要转换为控制台输出; 否则就是在控制台输出,不需要转换
      fflush(stdout);
      dup2(save_stdout_no ,fileno(stdout));
      close(save_stdout_no);
      save_stdout_no = -1; // 在控制台输出就是 -1
    }
  }
}

int main ()
{

  puts("1");  // 控制台
  TestDup("output.log");  // 转为 output.log
  puts("2");
  TestDup(NULL);  // 转为控制台
  puts("3");
  TestDup("output.log");  // 转为 output.log
  puts("4");
  TestDup(NULL);  // 转为控制台
  puts("end");

  return 0;
}

        程序运行结果为 1 3 end 输出在控制台,而 2 4 输出在 output.log 文件中。但 msvc 编译器下运行结果有误,mingw 编译器下运行结果无误。原因暂且未知。

        此外,注意 static 的用法,用 static 定义的变量,重新定义是不影响其变量值的。

void TestStatic(){

  static int a = 1;
  a++;
  printf("a: %d\n", a);  
}

int main ()
{
  TestStatic();  // 2
  TestStatic();  // 3
  TestStatic();  // 4
  TestStatic();  // 5
  TestStatic();  // 6
    
  return 0;
}

3. 其他想法

        1)不同文件的文件流互相转化,应该可以使用 freopen() 函数可以完成

        2)对 stdout 不一定要使用 freopen() 函数,用文件描述符完成所有的功能

        3)不同文件的文件流相互转化,应该也可以使用文件描述符完成

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值