实验六:流类库与I/O
Part 1
/*问题描述*/
1. 合并两个文件到新文件中。文件名均从键盘输入。 运行程序,结合运行结果及源码中注释,理解和体会文件I/O的方法。
/*代码如下*/
#include <iostream> #include <fstream> #include <string> #include <cstdlib> using namespace std; int main() { string filename1, filename2, newfilename; cout << "输入要合并的两个文件名: "; cin >> filename1 >> filename2; cout << "输入合并后新文件名: "; cin >> newfilename; ofstream fout; // 输出文件流对象 ifstream fin; // 输入文件流对象 fin.open(filename1); // 将输入文件流对象fin与文件filename1建立关联 if (!fin.is_open()) { // 如果打开文件失败,则输出错误提示信息并退出 cerr << "fail to open file " << filename1 << endl; system("pause"); exit(0); } fout.open(newfilename); // 将输出文件流对象fout与文件newfilename建立关联 if (!fin.is_open()) { // 如果创建/打开文件失败,输出错误提示信息并退出 cerr << "fail to open file " << newfilename << endl; system("pause"); exit(0); } char ch; // 从文件输入流对象fin中获取字符,并将其插入到文件输出流对象fout中 while (fin.get(ch)) fout << ch; fin.close(); // 关闭文件输入流对象fin与文件filename1的关联 fout << endl; // 向文件输出流对象fout中插入换行 fin.open(filename2); // 将输入文件流对象fin与文件filename2建立关联 if (!fin.is_open()) { // 如果打开文件失败,则输出错误提示信息并退出 cerr << "fail to open file " << filename2 << endl; system("pause"); exit(0); } // 从文件输入流对象fin中获取字符,并将其插入到文件输出流对象fout中 while (fin.get(ch)) fout << ch; fin.close(); // 关闭文件输入流对象fin与文件filename2的关联 fout.close(); // 关闭文件输出流对象fout与文件newfilename的关联 system("pause"); return 0; }
/*运行截图*/
Part 2
/*问题描述*/
使用文件I/O流,以文本方式打开Part1中合并后的文件,在文件最后一行添加字符"merge successfully. "
/*代码如下*/
1 #include<iostream> 2 #include<fstream> 3 #include<string> 4 using namespace std; 5 6 int main() { 7 string filename, str; 8 9 cout << "请输入要追加内容的文件名:"; 10 cin >> filename; 11 cout << endl << "请输入要追加的内容:"; 12 getline(cin, str,'t'); 13 14 ofstream out(filename,ios_base::app);//打开一个输出文件用于在文件尾部添加数据 15 if (out.is_open()) { 16 out << str; 17 out.close(); 18 } 19 system("pause"); 20 return 0; 21 }
/*运行截图*/
追加前:
追加后:
Part 3
说明:下面的两个程序都是基于每一行为单位来处理的,有了这个概念,应该会易于理解一些。
/*问题描述*/
1. 已知名单列表文件list.txt。编写一个应用程序,实现从名单中随机抽点n位同学(n由键盘输入),在屏幕上显 示结果,同时也将结果写入文本文件,文件名自动读取当天系统日期,如20190611.txt。
/*代码如下*/
*利用了老师提供的获取当前系统日期的函数工具,这里不再列出。
1 #include <iostream> 2 #include<fstream> 3 #include<sstream> 4 #include <string> 5 #include<ctime> 6 #include <cstdlib> 7 #include "utils.h" 8 9 using namespace std; 10 11 int main() { 12 13 string filename, luckydogs,filename0; 14 filename = getCurrentDate(); 15 filename += ".txt";//追加文件格式为txt 16 int num,lines=0,line=0; 17 cout << "请输入要抽取人员的文件名:"; 18 cin >> filename0; 19 cout << endl << "请输入要抽取的人数:"; 20 cin >> num; 21 string temp;//中转字符串 22 string arr[100];//用于存放文件中成员信息的二维字符串 23 ofstream fout; 24 ifstream fin; 25 26 fin.open(filename0,ios_base::in);//只读模式打开待读取文件 27 if (fin) { 28 while (getline(fin, temp)) { 29 arr[lines++] = temp;//同时利用lines来统计文件有多少行,方便下面随机抽人 30 } 31 fin.close(); 32 }//将名单中的人员信息全部读入一个二维字符串 33 for (int i = 1; i <= num; i++) { 34 35 srand(time(0));/*使用当前时间作为随机生成器的种子*/ 36 int random = rand(); 37 line += 1 + rand() % lines;/*可随机取得0-总行数(lines)之间的任意数*/ 38 cout << arr[line%lines] << endl; 39 40 fout.open(filename,ios_base::app);//以追加模式打开文件,否则之前写入的数据会消失,只剩最后写入的那一行 41 fout << arr[line%lines] << endl; 42 fout.close(); 43 } 44 45 system("pause"); 46 47 return 0; 48 } 49
/*运行截图*/
/*选做部分*/
在我们抽取人数较少的情况下可能不会出现重复的人选,但是一旦抽的人比较多,可能会出现重复抽取。这里采用添加标记的办法来判断是否已经被抽取。
更改部分的代码:
1 for (int i = 1; i <= num; i++) { 2 3 srand(time(0));/*使用当前时间作为随机生成器的种子*/ 4 int random = rand(); 5 line += 1 + rand() % lines;/*可随机取得0-总行数(lines)之间的任意数*/ 6 if (arr[i][arr[i].length() != '!']) {//判断是否有标记。 7 cout << arr[line%lines] << endl; 8 9 fout.open(filename, ios_base::app);//以追加模式打开文件,否则之前写入的数据会消失,只剩最后写入的那一行 10 fout << arr[line%lines] << endl; 11 fout.close(); 12 arr[line%lines] += "!";//添加标记,用于判断是否已经被抽取 13 } 14 else 15 continue; 16 }
/*问题描述*/
2、 编程统计英文文本文件中字符数(包括空格)、单词数、行数。文件名由键盘输入。
/*代码如下*/
1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<string> 5 using namespace std; 6 7 int main() { 8 string filename, temp; 9 string arr[100]; 10 int lines = 0,sum_char=0,sum_word=0; 11 cout << "请输入需要统计的英文文件名:"; 12 cin >> filename; 13 14 ifstream fin; 15 fin.open(filename, ios_base::in);//只读方式打开文件 16 if (fin) { 17 while (getline(fin, temp)) { 18 arr[lines++] = temp; 19 for (int i = 0; i< temp.length(); i++) {//顺便通过temp将单词总数统计一下 20 if ((temp[i] != ' ') && (temp[i + 1] == ' '))//避免两个单词之间存在多个空格,所以这样统计单词数 21 sum_word++; 22 } 23 sum_word++;//按照上述方法统计单词数每行会少统计一个,所以再自增一次 24 } 25 fin.close(); 26 }//将文件中的内容全部读入一个二维字符串,且利用lines计算行数 27 28 for (int i = 0; i < lines; i++) 29 sum_char += arr[i].length();//获取每一行的长度即每一行的字符数目 30 31 cout << "字符总数为:" << sum_char << endl; 32 cout << "单词数为:" << sum_word << endl; 33 cout << "行数为:" << lines << endl; 34 35 system("pause"); 36 return 0; 37 }
/*运行截图*/
Part 4
个人总结与体会
怎么说,我心里是那个悔啊,后悔当时学习这个章节的时候没有好好学,以至于啥都不懂,所以这么些内容我竟然写了近四个小时。。。
一点点摸索倒是懂了一些,emmm,先说一些自己的体会啥的吧。
一:istream和ostream的方法
具体详细的内容这里不做介绍
1、除了cout还有方法比如:put()和write(),前者是显示字符后者是显示字符串。还要关注一些格式控制函数等。
2、出去cin外,主要是get()和getline(),这里不做详细说明。还有一些如:read()(读取指定数目的字节)、peek()(返回输入中的下一个字符)、gcount()(返回最后一个非格式化抽取方法读取的字符数)和putback()(将一个字符插入到输入字符串中,被插入的字符将是下一条输入语句读取的第一个字符)等。这些都是挺有意思的,大家不妨找来资料好好翻一下,只学课本上的怕是距离掌握C++这门语言还差得远。
二:关于文件的输入输出
1、明白一些基础的概念啥的,比如:fstream这个类是从iostream类派生而来的,而后者基于istream和ostream这两个类,因此它继承了它们的方法。它还继承了两个缓冲区,一个用于输入,一个用于输出,并能同步化这两个缓冲区的处理。也就是说,当程序读写文件时它能协调地移动输入缓冲区的输入指针和输出缓冲区的输出指针。
2、接着,我们要解决的问题是要使用何种文件模式,是读取文件还是写入文件。读取文件须使用ios_base::in,此处不讨论二进制情况;写入文件须使用ios_base::out或ios_base::app,搞清楚这两个的区别。
3、还有呢,像是需要在文件中移动的话,有seekp()和seekg(),这两个也有着不同的查找找方式,关于常量ios_base::beg和ios_base::cur,ios_base::end等的使用又存在哪些区别呢。
4、。。。。。。我太菜了,就不胡扯了。但是有个小建议,过程中我遇到不会的地方我去CSDN上查找有用的信息,或许是我太垃圾了吧,有些看似有用的东西却用不起来,最后还是不免自己看书摸索出来的,安利一下C++ primer(plus)买一本在身边不无坏处。
三:胡扯了这么多我貌似还没说我遇到了哪些坑啊,,,emmm,遇到的坑太多了,我这个垃圾就不写出来了,以免丢人现眼。。。
Part 5
互评地址:
1、https://www.cnblogs.com/debuild/p/11010111.html
2、https://www.cnblogs.com/wjh1022/p/11028328.html
3、https://www.cnblogs.com/mzy-1229/p/11031672.htm