(八十九)txt文档的输入和输出

简介:

准确的说,不仅仅是TXT,也可以是无格式文件,或者其他后缀的文件,但打开方式是通过.txt方式(如记事本等)打开的


写入文本文件:

要操作txt文档,首先要有头文件<fstream>,有点类似<iostream>。

然后要创建一个ofstream的对象的对象名。具体格式为:

ofstream 对象名

对象名可以任意使用,例如abc,def等,之后通过他,来操纵相应的文件。

当使用: 对象名.open("文件名");  时,实际上就是将对象名指向了这个文件。

然后以后可以通过使用对象名,来输入/输出这个文件了。

假如open的文件不存在,那么这个open将自动创建对应名字的文件。

假如open的文件存在,那么这个open,将会舍弃文件中的内容。(除非使用其他办法修改这种行为)


注意:原来的内容会丢失!!

 

 

代码:

#include<iostream>
#include<fstream>
#include<string>

int main()
{
	using namespace std;
	int a;
	string b;
	char c[10];
	double d;
	ofstream abc;	//声明一个ofstream对象,其对象名为abc,可以改为其他名字,但总之,abc将在下面对应一个文件
	abc.open("abc.txt");	//让abc open一个txt文件,其文件名为abc.txt

	cout << "以下输入char类型字符串c[10]: ";
	cin.getline(c, 10);	//读取一整行给c,长度为10个字符。其实这里应该填9,因为虽然字符串c的长度为10,但最后一个应该为空字符\0
	cout << "以下输入int类型变量a: ";
	cin >> a;	//读取一个int类型的变量
	cout << "以下输入string类型字符串b: ";
	cin.sync();	//由于上面的cin在读取的时候没有舍弃换行符,因此需要使用清除缓存区,将换行符清除掉。
	getline(cin,b);	//读取输入的一行字符(遇到换行符为止),将其赋值给变量b
	cout << "以下输入double类型d: ";
	cin >> d;	//要求用户输入,并读取double变量d
	
	cout << fixed;	//以普通方式输出,并非科学计数法,例如123.111,而不是1.23e2之类
	cout.precision(2);	//设置小数点后精度为2位
	cout.setf(ios_base::showpoint);	//显示浮点数后的小数点,非浮点数不显示
	cout << "int类型变量a:" << a << endl;
	cout << "string类型变量b:" << b<< endl;
	cout << "char类型变量c:" <<c << endl;
	cout << "double类型变量d:" << d<< endl;

	abc << fixed;	//对abc这个对象来说,以普通方式输出,并非科学计数法,例如123.111,而不是1.23e2之类
	abc.precision(10);	//对abc这个对象,精度小数点后10位
	abc.setf(ios_base::showpoint);	//对abc这个对象来说,显示浮点数小数点后的0
	abc << "变量a:" << a << endl;	//这段以下的都是输入到abc对象中的内容
	abc << "变量b:" << b << endl;
	abc << "变量c:" << c << endl;
	abc << "变量d:" << d << endl;

	abc.close();	//关闭abc这个fstream对象,假如不写的这行代码的话,默认是在输入结束后关闭
	system("pause");
	return 0;

}

说明:

总的来说,以上代码的目的是为了将文字写入 文本文件 之中。为了达成以上目的,需要做以下工作:

①包含头文件<fstream>;

 

②头文件fstream定义了一个用于处理输出的ofstream类(意思是指想使用ofstream的前提是,使用了头文件fstream么?在这个头文件里,告诉编译器怎么用fstream?类似头文件string里面包含了类型名string么?

 

③声明一个ofstream类对象,例如ofstream abc就是声明一个变量名为abc的对象,

在下面写入文本文件时,这个abc << "变量a:" << a << endl; 就是写入文本文件(所对应的ofstream对象是abc)。可以理解为,给abc这个对象,写入内容“变量a:”后面加变量a外加后面加一个换行符。

 

④使用名称空间std,例如假如在开头不使用using namespace std;,那么后面就不能直接用ofstream abc,而是std::ofstream abc了。

 

⑤需要将声明的ofstream类对象abc与文件关联起来,例如使用open()方法;

如代码abc.open("abc.txt"),就是将abc.txt文件和ofstream类对象abc关联起来了。

 

⑥使用完文件后,应该使用close()将文件关闭。

例如使用代码:abc.close()

 

⑦可使用ofstream类对象名和运算符“<<”来输出各种类型的数据。(体现在输出到文件里)

 

⑧也可以使用C-风格字符串作为文件名:如代码:

#include<iostream>
#include<fstream>

int main()
{
	using namespace std;
	int a = 111;
	ofstream bbb;
	char b[10];	//定义一个字符串b,成员为10(注意最后一个应为空字符)
	cin >> b;	//输入一个C-风格字符串,用户可以自行输入,不超即可
	bbb.open(b);	//打开一个文件,文件名为字符串b的值(即用户输入的内容)。这个文件所指向的对象为ofstream类对象bbb
	bbb << a << endl;	//对对象bbb输入变量a(其值为111),再输入一个换行符。
	system("Pause");
	return 0;
}

效果为:当输入字符“m”时,在文件夹中创建一个文件名为m的文件,m的文件利用文本文件方式打开时,里面的内容为111,且在之后换行(有第二行,但内容为空)。

 

备注:使用string类替代C-风格字符串char b[10],经实际测试也可以。

即:文件名不一定需要是xxx.txt这种格式,也可以直接是xxx,但由于文件名没有.txt后缀,不能直接通过记事本等方式打开,需要在打开方式中选择使用记事本。

 

⑨不存在的文件,在open的时候,会自动进行创建。

 

 

读取文本文件:

以上是将内容写入到文本文件。写入方式是对象名(对应某个文本文件的变量名),然后是替代cout的位置,其他很类似cout的输出方式,只不过cout是将内容输出到屏幕上,而其是将内容输出到文件之中。

 

与写入到文件之中对应的,就是读取。即将文件中的内容读取到程序之中。

 

正如写入类似cout,读取则类似cin。

读取文件应该具有以下特色:

①包含头文件fstream(写入和读取是一个头文件);

 

②该头文件fastream定义了一个用于处理输入的ifstream类(写入是ofstream类)(in和out是对程序的in或者out,in是指写入到程序之中——即读取文件或者用户输入,out是指输出到程序之外,即写入到文件之中,或者输出到屏幕之上);

 

③声明一个或者多个ifstream对象(就像声明写入文件的ofstream对象那样做一样);

 

④指定名称空间std,使用方法同ofstream(即使用using或者在ifstream前面加std::)。

 

⑤使用ifstream对象名和运算符>>来读取各种类型的数据。(就像cin>>那样)

 

⑥可以使用ifstream对象和get()来读取一个字符,使用getline()来读取一行字符(同样类似cin那样使用);

 

⑦可以结合使用ifstream和eof()、fail()等方法来判断输入是否成功。

 

⑧ifstream对象本身用作测试条件时,如果读取内容的最后一个(只有一个则第一个就是最后一个)被读取成功,返回值为true,如果读取失败,则转为false(就像cin就是读取成功返回true,失败返回false;而!cin读取失败返回true,成功返回false);

 

注意:cin实质上就是iostream这个头文件预先定义好的istream对象。

 

验证以上如代码:

#include<iostream>
#include<fstream>	//在使用ifstream和ofstream时需要
#include<string>
#include<windows.h>	//在使用Sleep(1000)时需要

int main()
{
	using namespace std;
	char a[15];
	string b,c;
	string d[5];
	string abc;
	ifstream dd;	//创建一个ifstream类对象dd
	
	//打开一个文件
	cout << "请输入一个文件名,如果能读取,则读取,如果不能读取,将读取abc.txt。" << endl;
	cout << "在这里输入:";
	cin >> abc;
	dd.open(abc);	//对象名.open(C-风格字符串)是将该字符串所代表的文件名和对象名dd关联起来。
	if (dd.is_open())	//如果能够成功打开,那么对象名.is_open()将返回true值,否则返回false值
	{
		cout << "你输入的文件名" << abc << "打开成功!" << endl;
	}
	else
	{
		cout << "你输入了错误的文件名,现将打开文件abc.txt" << endl;
		dd.open("abc.txt");	//将ifstream对象dd和文件abc.txt关联起来。
	}
	
	cout << "等待1秒钟" << endl;
	Sleep(1000);	//大写的S开头,等待1000毫秒

	dd.getline(a, 16);	//类同cin.getline(变量名,长度);需要注意的是,长度应该超出文件中某一行的长度。不然会导致之后无法无法读取。
	//即假如16改为6,而文件第一行的长度超过6,那么之后的getline(dd,b)和getline(dd,c)将无法正常读取。
	getline(dd, b);	//读取一行,由于是string类型,因此是getline(对象名,变量名),对象名指ifstream类的对象名。
	cout << a << endl;
	cout << b << endl;

	//以下是用循环来读取文本文件,并输出到屏幕上
	for (int i = 0;dd >> d[i];i++)	//dd>d[i]指给string类数组d输入数据,输入成功则返回值为true,可以继续循环,输入失败则为false,结束for循环
	cout << d[i] << endl;

	//for (int i = 0;dd.good();i++)	//这个for和之前被屏蔽的for,其作用是一样的。只不过上面那个for,直接通过循环判断来读取内容,这里需要额外进行循环判断
								//另外,dd.good()的意思是,判断输入流是否正确,例如需要输入int类型的时候输入了一个char类型。则返回值为false。格式为:对象名.good()
	//{
	//	dd >> d[i];
	//	cout << d[i] << endl;
	//}

	//假如无法读取,返回提示
	if (!dd)	//dd的意思是,如果还能读取,则为true,加了!后,如果还能读取,为false,不能读取,为true
	{
		cout << "没有可读取的内容了" << endl;	//不能读取的时候,输出这行文字
	}
	cout << "读取结束~~" << endl;	//结束时输出这行文字

	system("pause");
	return 0;
}

输出:


请输入一个文件名,如果能读取,则读取,如果不能读取,将读取abc.txt。
在这里输入:gg
你输入了错误的文件名,现将打开文件abc.txt
等待1秒钟
变量a:434
变量b:ggf
变量c:hnnn
d变量d:33.1111100000
没有可读取的内容了
读取结束~~
请按任意键继续. . .

总结:

①当我们需要判断是否正确打开一个文件时,我们使用:对象名.is_open()

假如能够打开,返回值为true,假如无法打开(比如说输错文件名了),那么返回值为false。

 

②fail(),good()的区别,还有bad()等,前两个能用,但是并不知道其到底差别在哪里。还有.eof(),如何区分其用处?

推测是无法读取了,.fail().good()会返回true,但不一定是到文件尾了,可能是文件错误等。这个时候.eof()如果返回true,那么的确是到文件尾了。但若返回false,那就是出错了?

 

③假如要判断是否在文件尾,可以用  对象名.eof(),假如在文件尾了,返回值为true。不在文件尾,返回值为false。即,读取完所有内容时,返回值为true。

PS:只有在读取的时候,无返回值了,.eof()的返回值才为false。假如没有读取(例如dd>>变量名;在文件末尾,发现无法读取了,于是.eof()才会返回true值)。

 

eof()、good()、对象>>的区别:

假设对象名为 ifstream abc;变量名例如是string类型的变量fff;

 

————文件名ppp—————

——————————————

这个时候,代码为:

ifstream abc;
abc.open("ppp");	//之所以要加双引号,是因为要和可能的变量名ppp区分开
abc >> fff;


 

这个时候,若在之后加上代码:

if (!abc.good()) cout << "读取到末尾" << endl;


分析:因为在 abc >> fff;这段代码,已经读取到文件尾了。于是,abc.good()返回的内容是false,加上!则为true,于是输出“读取到末尾”这段话。

 

若加上的是代码:

if (abc.eof()) cout << "读取到末尾" << endl;


分析:因为abc>>fff已经读取了字符串abcdefg,文件到结尾了,于是abc.eof()的返回值为true(因为编译器在之前的abc>>fff已经检测到了文件尾)。于是if的判断语句为真,执行输出。

 

若是加上代码

abc >> fff;	//这行表示再次读取到变量fff中(注意,之前已经读取到文件尾了,另外fff换成另外一个其他类型的变量也可以)
if (abc.fail()) cout << "读取到文件尾" << endl;

分析:假如没有加入第二段abc>>fff,那么abc.fail()返回值为false。因为加入了第二句abc>>fff,于是,abc.fail()的返回值为true。那么就执行了输出语句。

 



按照说明:

①当程序读取文件时,若没有超过eof(例如最后是10个字符,只读取了10个字符,比如abc.getline(fff, 10);这种形式,或者只读取了前9个或更少)。那么就abc.eof()的返回值将为false。因为程序并没有遇见eof(文件尾);

 

②假如程序读取文件的时候,超过文件尾,即假设最后只有10个字符,但是读取了11个字符或者更多,或者是读取数字123的时候,使用了类型为int的变量。那么这个时候,程序遇见了eof,则abc.eof()的返回值为true;

 

③假如遇见了类型不匹配的情况。例如我们需要输入int类型的数据时(例如需要数值123),反而遇见了字符(例如abc),那么abc.fail()的返回值将为true。否则将为false。

 

推断:当能继续读取(未遇见eof,且读取未遇见问题)那么abc.good()将返回true。否则返回false。

A.假设文件内容有两行,第一行abcdefg,第二行空。那么代码:


int fff;
ifstream abc;
abc.open("fff.txt");
abc >> fff;
cout << fff << endl;
if (abc.fail())cout << "abc.fail()返回值为true" << endl;
if (abc.good())cout << "abc.good()返回值为true" << endl;
if (!abc.eof())cout << "abc.eof(返回值为false" << endl;


输出为:

-858993460
abc.fail()返回值为true
abc.eof(返回值为false


 

原因在于fff为int类型,读取错误的时候,输入流将保留。所以没有读取为eof。

 

B.假如把int类型改为string类型,那么输出为:

abcdefg
abc.good()返回值为true
abc.eof(返回值为false

原因在于没有读取错误,也没有遇见文件尾。

 

C.假如在B的基础上,把文件的第二行删除(即使他是空的),只剩下第一行。

那么输出为:

abcdefg

原因在于这个时候,遇见eof了,所以第三行判断代码未通过(注意,前面有一个感叹号);

又因为没有读取通过,所以第一行代码判断未通过;

又因为虽然类型正确,但遇见eof了,所以第二行代码也未通过。

 

⑤按照说明,方法good()指出最后一次读取输入的操作是否成功。

但根据个人经验,假如读取输入失败,的确good()会返回false,但是若是读取到结尾,也会返回false,即使最后一次读取成功了。如上面④中的C情况。

 

⑥除此之外,还有abc>>fff这种,将对象abc所对应的内容输入到fff之中。

假如可以输入,那么其表达式的返回值为true,否则为false。

因此,若需要连续读取的时候,可以使用while。例如

while(abc>>fff);	 //分号表示在判断语句后是空语句,无限循环判断语句即可。

将输入的内容,全部赋值给fff(但缺点是,前面的赋值将被最后的赋值所覆盖)。

 

⑦文件名要么在括号里,用双引号标注起来,要么使用C-风格变量名(测试string类变量名也可以),将其值赋给文件名。

例如:

char a[10];	//字符串a
cin >> a;	//用户输入,比如说游戏中的角色名,然后保存的时候,以这个角色名为存档名保存,当然,这里是读取,并不是保存。输出需要使用ofstream
ifstream abc;	//ifstream类对象abc
abc.open(a);	//假如用户输入gg,那么文件名为gg
ifstream def;	//ifstream类对象def
def.open("abc");	//文件名为abc,这里没有加后缀,也可以加后缀


 

具体使用哪种方式,根据实际需要而定。

 

⑧对象名的使用方式,几乎和cin的使用方式一样,可以参考使用。

假如ifstream aaa,那么例如!cin和!aaa机制是几乎是一样的,只不过一个是面对用户输入流,一个是面对来自文件的输入流。

 


目录
相关文章
|
3月前
|
数据采集 数据安全/隐私保护 Python
Python 快速合并PDF表格转换输出CSV文件
Python 快速合并PDF表格转换输出CSV文件
45 0
Python 快速合并PDF表格转换输出CSV文件
|
3月前
|
存储 C++
第七章:C++中的输入与输出
第七章:C++中的输入与输出
28 0
|
3月前
|
数据安全/隐私保护 Python
Python办公自动化【Word转换PDF、PDF读取内容、PDF合并文件、PDF拆分文件、PDF加密文件、PPT基本操作-增加幻灯片、增加内容】(六)-全面详解(学习总结---从入门到深化)(下)
Python办公自动化【Word转换PDF、PDF读取内容、PDF合并文件、PDF拆分文件、PDF加密文件、PPT基本操作-增加幻灯片、增加内容】(六)-全面详解(学习总结---从入门到深化)
34 1
|
3月前
|
数据安全/隐私保护 Python Windows
Python办公自动化【Word转换PDF、PDF读取内容、PDF合并文件、PDF拆分文件、PDF加密文件、PPT基本操作-增加幻灯片、增加内容】(六)-全面详解(学习总结---从入门到深化)(上)
Python办公自动化【Word转换PDF、PDF读取内容、PDF合并文件、PDF拆分文件、PDF加密文件、PPT基本操作-增加幻灯片、增加内容】(六)-全面详解(学习总结---从入门到深化)
52 0
|
9月前
成信大ENVI_IDL第三周课堂内容1:读取OMI数据(HDF5文件)以及输出+解析
成信大ENVI_IDL第三周课堂内容1:读取OMI数据(HDF5文件)以及输出+解析
109 0
|
11月前
(模拟菜单选择实现)## 存入你的基本信息,在zhangsan.txt文件中## 显示你的基本信息## 统计zhangsan.txt含有good的文本数
(模拟菜单选择实现)## 存入你的基本信息,在zhangsan.txt文件中## 显示你的基本信息## 统计zhangsan.txt含有good的文本数
|
Python
Python打印2018年的日历(【问题描述】 打印2018年的日历 【输入形式】 【输出形式】 【样例输入】 【样例输出】)
Python打印2018年的日历(【问题描述】 打印2018年的日历 【输入形式】 【输出形式】 【样例输入】 【样例输出】)
174 0
Python打印2018年的日历(【问题描述】 打印2018年的日历 【输入形式】 【输出形式】 【样例输入】 【样例输出】)
|
机器学习/深度学习 Shell Python
[oeasy]python0022_框架标题的制作_banner_结尾字符串_end
[oeasy]python0022_框架标题的制作_banner_结尾字符串_end
82 0
[oeasy]python0022_框架标题的制作_banner_结尾字符串_end
|
SQL 数据库
无事来学学--Kettle中输入,输出组件的使用(三)
CSV文件 一种带有固定格式的文本文件。注意:获取字段的时候可以调整自己的字段类型,格式,满足自己的需求哦。
133 0
|
JSON Oracle 关系型数据库
无事来学学--Kettle中输入,输出组件的使用(二)
CSV文件 一种带有固定格式的文本文件。注意:获取字段的时候可以调整自己的字段类型,格式,满足自己的需求哦。
346 0