IO标准库:操作文件时应该注意的一些地方

本文详细介绍了C++ IO流库在操作文件时应注意的几点:流对象不支持复制或赋值,如何正确传递和返回IO对象;clear()函数的使用场景及其与setstate()的区别;文件模式的解释,包括in、out、trunc、app等模式的含义;缓冲区何时被刷新的情况解析;以及一个流对象操作多个文件的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、流对象不支持复制或者赋值操作

1、只有支持复制操作的元素类型可以存储在vector或其他容器中,由于流对象不能复制,因此不能存储在vector中,即不存在存储流对象的

vector 或其他容器;

2、形参或返回类型也不能为流类型。如果需要传递或返回 IO对象,则必须传递或返回指向该对象的指针或引用;

3、一般情况下,如果要传递 IO 对象以便对它进行读写,可用非 const 引用的方式传递这个流对象。对IO 对象的读写会改变它的状态,因此

引用必须是非const 的。


二、关于clear()函数的使用

1、clear函数的默认实参是goodbit,意思是设置流的状态位为goodbit,同理strm.clear(std::failbit)是将流的状态位设置为failbit;

2、strm.clear()通常与strm.sync()搭配使用,sync方法的作用是清除输入流的缓冲区,如下面的例子,当输入流要求输入的是整形,而用户

却输入非整形的字符,这会导致流的状态位为failbit,调用strm.clear()后将流的状态位设置为goodbit,但是用户输入的内容仍在cin的缓冲区

中,即下次再调用cin >> ival时,返回给ival的依然是存在缓冲区中非法的值,此时cin >> ival 不再生效,而是直接跳过要求用户输入的这个工

作,阻止这个程序行为就是清空cin的缓冲区cin.sync()。

void test_clear_sync(){
	int ival;
	while(std::cin >> ival, !std::cin.eof() ){
		if( std::cin.bad() ){
			throw std::runtime_error("Input stream is error!");
		}
		if( std::cin.fail() ){
			std::cout << "Please enter a number type!" << std::endl;
			std::cin.clear();
			std::cin.sync();
			continue;
		}
		std::cout << "ival:" << ival << std::endl;
	}
}

三、setstate()与clear()的区别:

流的状态标志值:goodbit:0,eofbit:1,failbit:2,badbit:4

1、setstate通常用于设置流的错误状态,比如把goodbit的状态设置成eofbit,failbit,badbit三种状态之一,或多种错误状态叠加,这个过程

不可逆,即把流的goodbit设置成其他的错误状态时,不同通过调用strm.setstate(std::ios::goodbit)把流恢复为有效状态,这种方式无效:

void test_setstate_1()
{
	// 同时设置多个状态值:
	std::cin.setstate(std::istream::badbit | std::istream::failbit);
	std::cout << std::cin.rdstate() << std::endl;//6
	std::cin.setstate(std::istream::goodbit);
	std::cout << std::cin.rdstate() << std::endl;//6,错误状态值没有被更改
}

2、当流处于非goodbit状态时,恢复为有效状态做法是使用clear函数【clear函数的作用如第二点】,故正确的做法为:

void test_setstate_2()
{
	// 同时设置多个状态值:
	std::cin.setstate(std::istream::badbit | std::istream::failbit);
	std::cout << std::cin.rdstate() << std::endl;//6
	std::cin.clear();
	std::cout << std::cin.rdstate() << std::endl;//0,成功设置
}

四、文件模式

in打开文件做读操作
out打开文件做写操作
app在每次写之前找到文件尾
ate打开文件后立即将文件定位在文件尾
trunc打开文件时清空已存在的文件流
binary以二进制模式进行 IO 操作

1、默认情况,与 ifstream 流对象关联的文件将以 in 模式打开,该模式允许文件做读的操作;与 ofstream 关联的文件则以 out 模式打开;

fstream 对象以 in 和 out 模式同时打开。

2、以out 模式打开的文件会被清空。从效果来看,为 ofstream 对象指定 out 模式等效于同时指定了 out 和 trunc 模式。故对于用 ofstream

打开的文件,要保存文件中存在的数据,唯一方法是显式地指定 app 模式打开。

3、当文件同时以 in和 out 打开时不清空;

4、模式是文件的属性而不是流的属性;

5、以下为一个打开文件的程序:

// 应该返回void,因为返回的stream类型是不能复制的
std::ifstream& open_file( std::ifstream &input, const std::string &filename )
{
	if( input.is_open() )
	{
		input.close();
		input.clear();
	}
	input.open(filename, std::fstream::in);
	return input;
}

int main()
{
	//std::ifstream input; // input.is_open() 为 false
	std::ifstream input("test.txt"); // input.is_open() 为 true

	//错误:流不能复制,函数open_file应该返回void
	//input = open_file(input, "test.txt");
	open_file(input, "test.txt");
	return 0;
}

五、导致缓冲区被刷新的几种方式:

1、程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区;

2、在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新;

3、用操纵符显式地刷新缓冲区,例如行结束符 endl;

4、在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区;

5、可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区;

6、如果程序的执行的过程中崩溃了,则不会刷新缓冲区。

// 使用操作符显示刷新输出流缓冲区的三种方式:
void test_flush_buf()
{
	std::cout << "abc_";
	std::cout << "def_";
	std::cout << "ghi_";
	
	// 1.操作符flush,但不在输出中添加任何字符
	std::cout << std::flush;

	// 2.操作符endl,输出一个换行符并刷新缓冲区
	std::cout << std::endl;

	// 3.ends操作符,在缓冲区中插入空字符 null,然后后刷新【较少用】
	std::cout << std::ends;
	
}

// 使用unitbuf操作符清空缓冲区:
void test_unitbuf()
{
	// nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式
	std::cout << std::unitbuf << "first_" << "second_" << "third" << std::nounitbuf;
	// 相当于:
	std::cout << "first_" << "second_" << "third" << std::flush;
}

六、一个流对象操作多个文件

void test_mul_file()
{
	std::vector<std::string> files;
	files.push_back("t1.txt");
	files.push_back("t2.txt");
	files.push_back("t3.txt");

	std::ifstream input;
	std::string line;
	for( std::vector<std::string>::iterator it = files.begin(); it != files.end(); ++it )
	{
		input.open(*it, std::ifstream::in);
		if( !input )
		{
			std::cerr << "Error: can not open the file : " + (*it) << std::endl;
		}
		else
		{
			while( input.good() )
			{
				getline(input, line);
				std::cout << "File " << *it << ": " << line << std::endl;
			}
		}
		// 当使用一个流对象操作多个文件时,每次操作完一个文件之后记得要close流与当前文件的
		// 连接,并重新设置流的状态为goodbit:
		input.clear();
		//input.sync();// close动作会自动刷新缓冲区
		input.close();
		std::cout.clear();	
	}
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值