C++中文件重定向详解

前言

使用c++一段时间后,想从某data.input文件中读入数据,而不是从小黑窗里键盘输入。

或者想直接输出到某个data.txt文件,而不是打印在小黑窗里,就需要用到文件重定向

 

本文主要介绍3种方案。

C++中可以rdbuf()方案。

C中可以用freopen(),和 {fscanf,fprintf},两种方案。

顺带一些坑。

 

①C++ 实现方法

 

用好iostream里的cin.rdbuf()和cout.rdbuf函数,

以及ftream里的in和out两个rdbuf()函数。

 

1.1 无参数时,4个函数的返回值相同,都是各自buffer的指针

//istream和ostream的无参数rdbuf()

_Mysb * rdbuf() const
{    // return stream buffer pointer
	return (_Mystrbuf);
}


//ifstream和ofstream的无参数rdbuf()

_Myfb *rdbuf() const
{    // return pointer to file buffer
	return ((_Myfb *)&_Filebuffer);
}

 

1.2 cin.rdbuf()和cout.rdbuf有含参的重载形式

效果为设置传入的参数指针为自己的buffer指针,返回原buffer指针。

_Mysb *rdbuf(_Mysb *_Strbuf)
{	// set stream buffer pointer
	_Mysb *_Oldstrbuf = _Mystrbuf;
	_Mystrbuf = _Strbuf;
	clear();
	return (_Oldstrbuf);
}

 

1.3 C++实现案例

下面代码设置的fout默认是"w"模式,每次运行时,cout的输出会覆盖原内容。

也就是说无论运行下面代码多少遍获得的output.txt内容完全一致。

output.txt不存在时会自动创建文件。

想变成"rw"追加模式,只需要修改为fout("output.txt",ios::app);即可。


#include <iostream>
//#include <ostream>
#include <fstream>
using namespace std;
int main()
{
	ifstream fin("input.txt"); // 输入文件
	ofstream fout("output.txt"); //输出文件
	streambuf *cinbackup;
	streambuf *coutbackup;
	cinbackup = cin.rdbuf(fin.rdbuf()); //用 rdbuf() 重新定向,返回旧缓冲区指针
	coutbackup = cout.rdbuf(fout.rdbuf()); //用 rdbuf() 重新定向,返回旧缓冲区指针

	char a[100];
	cin >> a; //从input.txt文件读入
	cout << a << endl; //写入 output.txt

	//还原标准输入输出流
	cin.rdbuf(cinbackup); // 取消,恢复键盘输入
	cout.rdbuf(coutbackup); //取消,恢复屏幕输出

	fin.close();//随手关闭
	fout.close();//是好习惯

	return 0;
}

 

②C语言版本

 

2.1使用freopen()函数

其声明为

FILE *freopen( const char *filename, const char *mode, FILE *stream );

代码示例1

#include<stdio.h>

int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);

    int a,b;
    scanf("%d %d",&a,&b);
    printf("%d\n",a+b);

    fclose(stdin);//关闭文件 
    fclose(stdout);//关闭文件 
}

//如果想改回来,需要重新打开标准控制台设备文件,这个跟系统有关

//Windows系统下
freopen("CON", "r", stdin);
freopen("CON", "w", stdout);

//Linux系统下
freopen("/dev/console", "r", stdin);
freopen("/dev/console", "w", stdout);

//参考https://blog.csdn.net/qingchenwuhui/article/details/46456469

 

2.2使用fscanf、fprintf

需要先定义相关的FILE*指针

 

代码示例2

#include<iostream>
#include<fstream>

int main()
{
	//重定向输入
	FILE *in = fopen("input.txt", "r");
	fscanf(in, "%d %d", &num, &wNum);

	//重定向输出
	FILE *out = fopen("output.txt", "w");
	fprintf(out, "%.1lf", avg);

	//随手关闭,是好习惯
	fclose(in);
	fclose(out);

	return 0;
}

 

 

③常见的坑

 

3.1 fsprintf无效怎么办

【描述】函数fprintf使用之后,文件内容为空,输出没有被写入文件中。

【问题解析】

这是由于C中存在一种“缓存机制”。

为了减轻系统的实时I/O负担,使用fopen以"w“打开的文件,会默认分配一个buf缓冲区。

缓冲区的大小由系统头文件<stdio.h>中的BUFSIZ定义。

/* Buffered I/O macros */

#define BUFSIZ  512

//以上摘自Windows SDK 10.0.17134.0中的stdio.h头文件

直到buf缓冲区被填满,才会进行一次真正的写入操作,清空缓冲区;

=>或者程序员直接调用fflush()主动清空缓冲区,将内容写入文件;

=>或者使用fclose()结束一个stream的生命周期时,由函数自动清空缓冲区;

=>或者main()函数生命周期结束时,由系统自动清空缓冲区。

 

所以我们有2种比较合适的方式解决这个问题。

3.1.1 取消缓存机制,使用setbuf()函数

void setbuf(FILE* _Stream, char* _Buffer)

将fopen时自动分配的buf替换成我们指定的buf
如果指定的_Buffer = NULL,
则缓存机制失效,实时进行写入操作

代码示例

FILE *out = fopen("output.txt", "w");
setbuf(out,NULL);
fprintf(out, "%d", n);

 

3.1.2 主动清空缓冲区,使用fflush()函数

int fflush(FILE *stream);

代码示例

FILE *out = fopen("output.txt", "w");

fprintf(out, "%d", n);
fflush(out); //清空out的缓冲区,立即进行一次写操作


//还有一个fflushall(),无需参数,对所有已打开文件进行一次主动清空

一些关于fflush的补充

If the given stream was open for writing (or if it was open for updating and the last i/o operation was an output operation) any unwritten data in its output buffer is written to the file.

如果stream指向一个输出流,或者指向一个最后一次I/O操作是输出的更新流,那么fflush函数将把buffer内所有未处理的数据写入stream对应的文件。


If stream is a null pointer, all such streams are flushed.

如果我们设置参数为NULL,上述所有流都将被刷新。

 

注意,其他情况下,fflush(NULL)的行为是不确定的,与不同的编译器有关。

比如fflush(stdin ),stdin是一个输入流,不满足第一段说的open for writing or updating,因此有的编译器支持,有的编译器不支持,不可预料结果。

 

The stream remains open after this call

fflush不会关闭流。

 

A zero value indicates success.
If an error occurs, EOF is returned and the error indicator is set (see ferror).

如果正确处理,返回0。
如果发生写错误,fflush函数会给出错的流打上错误标记,并且返回EOF。
 

//setbuf与缓冲区详解请参考https://blog.csdn.net/zhoubl668/article/details/7076324

//关于fflush()参考http://www.cplusplus.com/reference/cstdio/fflush/

 

  • 16
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是第三版,增加了大量关于键盘缓冲区操作和输入、输出操作的知识讲解,并修改了多处前两版文字、语句错误的地方。 前两个版本由于我等级不够无法删除,此处留下前两版的地址,希望对大家有用。 第一版:http://download.csdn.net/source/3056070 第二版:http://download.csdn.net/source/3332359 以下为第三版本的目录: C/C++控制台界面编程(V 3) 1 目录 - 1 - 第一部分 控制台界面编程预备知识 1 1) Visual Studio 2005控制台程序的类型 1 2) 转义字符及格式化输入、输出 1 a) 制表符\t 2 b) 回退字符\b 4 c) ASCII码表 6 d) 以%开头的格式控制符 9 e) 数据流的格式设置 10 3) C和C++库的输入、输出操作 12 a) stdio.h的常用输入、输出函数 13 b) basic_stream的输入、输出操作 13 4) 键盘缓冲区处理 15 5) 关于C/C++的字符串拼接问题 17 6) 怎样从控制台复制粘贴文字 18 7) 将批处理bat转换为exe程序 18 8) 在Visual Studio 2005设置控制台程序的图标 18 9) 重定向控制台程序的输出 19 第二部分 控制台界面编程详解 20 1) 概述 20 2) 控制台文本窗口编程的一般控制步骤 21 3) 控制台窗口操作函数 21 4) 文本属性操作 25 5) 文本输出 28 6) 文本操作示例 28 7) 滚动和移动 34 8) 光标操作 36 9) 读取键盘信息 37 10) 读取鼠标信息 44 11) 结束语 46 第三部分 附录 1 1) 分数等级划分工具 1 a) controlio.h文件 1 b) Main.c文件 5 2) 简易俄罗斯方块 6 a) 代码Main.c文件 7 3) 模拟实现可用鼠标、键盘控制的菜单和窗口 11 这是第三版,增加了大量关于键盘缓冲区操作和输入、输出操作的知识讲解,并修改了多处前两版文字、语句错误的地方。 前两个版本由于我等级不够无法删除,此处留下前两版的地址,希望对大家有用。 第一版:http://download.csdn.net/source/3056070 第二版:http://download.csdn.net/source/3332359
该书共分成15个章节,由易到难,由浅及深的介绍了MFC的功能框架和实际运用。每个知识点都有对应的代码实例。学习起来快速而不费力。更重要的是不是扫描版本。看着舒服。 目录结构如下: 目 录 译者序 前言 第一部分 基础知识 第1章 窗口 2 1.1 窗口和API环境 2 1.1.1 三种类型窗口 2 1.1.2 客户区和非客户区 3 1.2 窗口和MFC环境 4 1.3 怎样应用MFC创建一个窗口 5 1.4 怎样使用MFC销毁一个窗口 9 1.4.1 捆绑到一个已有的窗口 9 1.4.2 窗口类 10 1.4.3 窗口进程 10 1.5 怎样使用MFC创建一个窗口类 11 1.5.1 使用AfxRegisterWndClass () 函数注册一个窗口类 11 1.5.2 使用AfxRegisterClass ()函数 创建一个窗口类 12 1.6 怎样销毁一个MFC窗口类 14 1.7 厂商安装的窗口类 14 1.8 其他类型窗口 15 1.9 桌面窗口 16 1.10 小结 16 第2章 类 18 2.1 基类 18 2.1.1 CObject 18 2.1.2 CCmdTarget 19 2.1.3 CWnd 19 2.2 应用程序、框架、文档和视图类 19 2.2.1 CWinApp(O/C/W) 20 2.2.2 CView (O/C/W) 21 2.3 其他用户界面类 22 2.3.1 通用控件类 23 2.3.2 菜单类 23 2.3.3 对话框类 24 2.3.4 控制条类 24 2.3.5 属性类 25 2.4 绘图类 25 2.4.1 设备环境类 25 2.4.2 图形对象类 25 2.5 文件类 26 2.6 数据库类 26 2.6.1 ODBC类 26 2.6.2 DAO类 27 2.7 数据集类 27 2.8 其他数据类 27 2.9 通信类 28 2.10 其他类 29 2.11 小结 31 第3章 消息处理 32 3.1 发送或寄送一个消息 32 3.1.1 发送一个消息 32 3.1.2 寄送一个消息 32 3.1.3 发送一个消息与寄送一个消息 的比较 32 3.2 怎样使用MFC发送一个消息 33 3.3 怎样用MFC寄送一个消息 33 3.4 三种类型的消息 34 3.4.1 窗口消息 34 3.4.2 命令消息 34 3.4.3 控件通知 34 3.5 MFC怎样接收一个寄送的消息 36 3.6 MFC怎样处理一个接收到的消息 36 3.7 处理用户界面的对象 44 3.8 创建自定义窗口消息 45 3.8.1 静态分配的窗口消息 45 3.8.2 动态分配的窗口消息 46 3.9 重定向消息 47 3.9.1 子分类和超分类 47 3.9.2 用MFC子分类窗口 48 3.9.3 重载OnCmdMsg ( ) 49 3.9.4 使用SetWindowsHookEx ( ) 49 3.9.5 使用SetCapture ( ) 49 3.9.6 专有的消息泵 50 3.10 小结 50 第4章 绘图 51 4.1 设备环境 51 4.2 在MFC环境创建一个设备环境 52 4.2.1 屏幕 52 4.2.2 打印机 53 4.2.3 内存 54 4.2.4 信息 54 4.3 绘图例程 55 4.3.1 画点 55 4.3.2 画线 55 4.3.3 画形状 55 4.3.4 形状填充和翻转 55 4.3.5 滚动 56 4.3.6 绘制文本 56 4.3.7 绘制位图和图标 56 4.4 绘图属性 56 4.4.1 设备环境属性 57 4.4.2 画线属性 58 4.4.3 形状填充属性 58 4.4.4 文本绘制属性 58 4.4.5 映像模式 59 4.4.6 调色板属性 62 4.4.7 混合属性 62 4.4.8 剪裁属性 63 4.4.9 位图绘制属性 64 4.5 元文件和路径 65 4.5.1 元文件 65 4.5.2 路径 66 4.6 颜色和调色板 66 4.6.1 抖动色 67 4.6.2 未经抖动色 67 4.6.3 系统调色板 67 4.6.4 使用系统调色板 68 4.6.5 动画色 71 4.7 控制什么时候在哪里绘图 71 4.7.1 处理WM_PAINT 71 4.7.2 只绘制被无效化的区域 72 4.7.3 处理WM_DRAWITEM 72 4.7.4 在其他时间绘图 73 4.8 小结 74 第二部分 用户界面实例 第5章 应用程序与环境 76 5.1 例1 规划MFC应用程序 76 5.2 例2 用AppWizard创建一个MFC 应用程序 79 5.3 例3 用ClassWizard创建一个类 83 5.4 例4 初始化应用程序屏幕 84 5.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值