准确的说,不仅仅是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机制是几乎是一样的,只不过一个是面对用户输入流,一个是面对来自文件的输入流。