第一次作业
码云项目地址:https://gitee.com/lonelyCloud/wc
个人psp:
PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
计划 | 10 | 10 |
.预估任务所需时间 | 10 | 10 |
开发 | 180 | 430 |
.需求分析(包括学习新技术) | 30 | 120 |
.生成设计文档 | 0 | 0 |
.设计复审 | 0 | 0 |
.代码规范 | 0 | 0 |
.具体设计 | 30 | 30 |
.具体编码 | 60 | 150 |
.代码复审 | 20 | 45 |
.测试 | 50 | 85 |
报告 | 50 | 60 |
.测试报告 | 10 | 20 |
.计算工作量 | 10 | 10 |
.事后总结 | 30 | 30 |
合计 | 240 | 500 |
解题思路:这是一个需要对文件进行操作的程序,拿到题目时我先决定了使用c++语言进行程序开发, 这个是必须最先确定的。随后需要找到的就是c++语言如何对文件进行操作,所以我查询了相关的书籍,找到了所需要的打开文件,读取文件字符,关闭文件的方法。接下来就要确定实现查询功能的具体算法,在知道了读取文件中的字符的方法后就很简单了,查询总的字符数就只需要在程序逐个读取字符的同时进行计数,在读取完成之后就得到了总的字符数;总的单词数的计数则比较复杂,c++语言里有I一个方法可以读取当前字符的下一个字符,这就是计算总的单词数的关键,如果当前字符是一个字母并且它的下一个字符不是字母,表示当前字符一个单词的最后一个字母,如果在逐个读取字符的时候遇到了这样的组合则表示已经读取了一个单词,这时进行计数,当文件读取完成之后就可以得到文件中总的单词数;最后是计算文件中的总行数,这个比较简单,只需要将字符与换行符进行比较,比较匹配事进行计数,在文件读取完成之后就可以得到总行数。
然后是将得到的查询结果保存到文件当中,用于保存记录的文件有几个可能存在的状态:1,在程序执行的时候不存在。2,程序执行的时候已经存在但文件为空。3,文件存在并且已经写入了记录。所以在打开文件时需要额外的检查,通过查询书籍得到了相关的参数:in|out|app,这个参数组合的功能是打开一个文件以供读写,存在时不覆盖,不存在时创建。这就达到了我所需要的要求。
程序实现过程:由于题目要求有4个操作符,所以原本打算在四个函数中实现各自功能,但是在具体编码的时候发现无法向函数中传递指向文件的方法,所以最后只能在主函数中实现了所有的功能。
程序开始首先查找所需要访问的文件,按照输入规则,除wc.exe以外输入的第一个有效的文件路径就是需要访问的文件路径,所以首先找到文件路径,将文件打开。接下来是实现操作的部分,根据输入的操作对文件进行对应的操作,操作完成之后关闭文件,防止资源泄漏。然后继续判断是否输入了保存操作和有效的用于保存操作记录的文件路径,如果两者都符合条件则进行保存操作,将之前进行了的操作所产生的查询结果保存到对应的文件当中,最后结束程序。
代码说明:
//找到命令行输入的查询文件的路径和名字 while (1) { file1.open(argv[i]); if (file1.fail()) { i++; if (argv[i] == NULL) { cout << "打开文件失败,退出程序" << endl; exit(0); } continue; } else { index = i; break; } }
这部分代码功能是寻找需要进行操作的文件路径,由于输入的命令储存在main()函数的argv[]数组中,所以需要逐个读取其中的变量以得到有效的文件路径,读取到之后就打开对应文件并且记录该路径在数组中的位置,后面保存操作记录时会用到文件名字。
while (!file1.eof()) { file1.get(ch); count1++; } cout << "总字符数:" << count1 << endl;
这部分代码为计算文件当中所有的字符,其中file1.get(ch)就是逐个读取文件中的字符,下面count1变量在初始化为0的前提下进行计数,file1.eof() 为真时表示文件读取结束,使用这个方法作为文件读取结束的标志。
while (!file1.eof()) { file1.get(ch); if (ch >= 'a'&&ch <= 'z' || ch >= 'A'&&ch <= 'Z')//判断当前字符是否为一个字母 { nextCh = file1.peek();//定义了一个字符变量,将当前字符的下一个字符赋给该字符变量 if (nextCh<'a'&&nextCh>'Z' || nextCh<'A' || nextCh>'z')//判断当前字符的下一个字符是否是一个字母 count2++; } } cout << "总单词数:" << count2 << endl;
这部分为统计文件当中单词总数的功能部分,file1.peek()方法为读取当前字符的下一个字符,通过之前叙述的方法可以得到文件中的总单词数。
while (!file1.eof()) { file1.get(ch); if (ch == '\n')count3++; } count3++; cout << "总行数:" << count3 << endl;
这部分为统计总行数的功能,就是见当前字符与换行符进行比较从而得到总行数。
if (argv[i] == NULL)exit(0); //有查询操作符却没有输入保存文件的有效路径和文件名,退出程序 if (strcmp(argv[i], "-o") == 0 && argv[i + 1] == NULL) { cout << "'-o'指令不能单独使用,违规操作,退出程序"; exit(0);
这两个分支语句用来判断是否输入了保存操作符合有效的用于保存查询记录的文件路径。
file2.open(argv[i + 1], ios::in | ios::out | ios::app); if (count1 != 0) file2 << argv[index] << ",总字符数:" << count1 << endl; if (count2 != 0) file2 << argv[index] << ",总单词数:" << count2 << endl; if (count3 != 0) file2 << argv[index] << ",总行数:" << count3 << endl; cout << "成功向记录文件写入记录,程序执行完毕" << endl; exit(0);
这部分就是具体写入查询结果的实现,由于用于储存三种操作查询结果的变量在程序开头都进行了置为0的初始化操作,所以如果变量为0则表示未进行相应的操作,则不执行相应的保存操作记录的操作。在写入记录完成之后就会关闭程序。
测试过程:在一个文件路径下我自己创建了几个转么用于测试的文件,文件类型有.c文件,.txt文件,.doc文件,并且有的写入了一些文字,有的则是空文件,在完成代码之后对文件都进行的操作,确保了程序的可执行性和正确性。
参考文献:
清华大学出版社出版的c++从入门到精通