写一个程序,统计自己C语言共写了多少行代码。ver2.00
概要
完成一个程序,作用是统计一个文件夹下面所有文件的代码行数。输入是一个文件夹的绝对路径,输出是代码行数。所以此程序的新特点有两个:
- 统计某一文件夹下的所有文件;
- 可以任意指定本机硬盘上任何位置的某一个文件夹。
前言
在上一篇随笔中熟悉了文件的基本操作。但仍然有改进的余地:统计特定文件时,还是需要手动输入文件名。如果文件数量很多怎么办?可不可以直接统计某个文件夹下面的所有文件的代码行数?今天解决的就是这个问题。
思考
我们已经解决了一个问题:写一个带有文件操作的C语言程序,输入文件名,输出此文件下的换行数。
考虑了一下现有的成果以及新增的目标,有需要更改的地方应该是输入,由文件名换成一个文件夹,然后通过程序扫描一遍这个文件夹下面所有的文件。然后读取所有的文件名,存放到数组里。再把字符串由fopen一个个调用,统计行数。细节差不多是这样,但总归要先扫描文件夹吧!
怎么扫描文件夹下面的文件?
搜索引擎搜索:C语言怎么扫描文件目录?
有找到几个链接,比较有用,可以参考:
比较可惜的是,上述网站提供的参考方法有使用函数opendir,查找了一下,发现这是一个在Linux系统下的函数。本人没有用过Linux。想了想,并没有直接开始搜索“安装Linux教程”,我心想:总有不用这个函数的方法吧!于是依旧在搜索引擎上不断地寻找。
找了接近一小时也无果,我打算换个问法。于是我在搜索引擎打入了:统计一个文件夹下文件
立刻映入我眼帘的就有一个黑科技,我惊呆了。
我立刻在桌面按照步骤进行实验。不得不说,看到结果,我非常满意。这不就我要的文件夹下面的所有文件名的字符串组合嘛!
立刻通过编程实现这一功能,效果拔群。
#include<stdio.h>
int main()
{
FILE *fp;
fp = fopen("TEXT.bat","w");
fputs("DIR *.* /B> LIST.TXT",fp);
fclose(fp);
return 0;
}
这里面有一行神秘的操作码,
DIR *.* /B> LIST.TXT
问题来了,这一行代码到底是什么呢?还是搜索引擎帮助你:)
大概知道了:
dir 显示目录中的文件和子目录列表;
/B 使用空格式(没有标题信息或摘要);
* . * (两个星号中间一个句点)就是说显示所有文件,文件名和扩展名没有限制。举例说明:如果是*.txt,则是显示所有扩展名为txt的文件;
最后面是字符串,很容易就知道是重定向输出的文件名。
好了。那么进行下一步的操作。我们考虑到一个文件夹只统计C语言代码的行数,所以这里我考虑只对.c后缀的文件进行这种操作。
#include<stdio.h>
int main()
{
FILE *fp;
fp = fopen("Text.bat","w");
fputs("DIR *.c /B> list.txt",fp);
fclose(fp);
fp=fopen("Text.bat","r");
fclose(fp);
return 0;
}
这儿遇到了第一个问题,运行可执行文件main.exe之后,文件夹内的文件情况如下图:
没有产生预期想要获得的文本文件list.txt。看来问题出在:
fp = fopen("Text1.bat","r");
这行语句上。因为,已经正常生成.bat文件,并且双击运行的话还是能生成文本文件,说明.bat文件没有问题,应该是打开文件的方式有问题。
立刻搜索:c语言打开bat文件。得到解决方法:
在程序中使用system() 函数。
假设bat文件的名称叫a.bat 即:
system("a.bat");
通过搜素来的方法,轻松解决这个问题。
#include<stdio.h>
int main()
{
FILE *fp;
fp = fopen("Text.bat","w");
fputs("DIR *.c /B> list.txt",fp);
fclose(fp);
system("Text.bat");
return 0;
}
编译后运行结果:
得到了我们想要的list.txt。也就是说.bat文件被正确地执行了。生成LIST的工作已经完成。现在已经有了存储文件名字符串的文本文件,下面只需要从这些文件中读取文件名,再调用上一篇随笔中实现的功能,即可实现这次需要添加的新功能了。
实现的简单的从list.txt中读取文件名。打开文件进行行数统计:
#include<stdio.h>
#include<Windows.h>
#include<string.h>
int main()
{
FILE *fp;
fp = fopen("Text.bat","w");
fputs("DIR *.c /B>list.txt",fp);
fclose(fp);
system("Text.bat");
/*~~~the end of creating file name list~~~*/
/*~~~the beginning of get .c file name from list~~~*/
static int count = 0;
FILE *fp1, *fp2;
fp1 = fopen("list.txt","r");
char s[100], singleline[1000];
while(fgets(s, 100, fp1))//get the name(one line) of a file from the list
{
// int len=strlen(s);
// if(s[len-1]=='\n') s[len-1]='\0'; what is this?
printf("%s: ",s);
fp2 = fopen(s,"r");//open the correct file, according to the file name
while(fgets(singleline, 1000, fp2))
{
count++;
}
printf("%d\n", count);
fclose(fp2);
}
printf("\n");
fclose(fp1);
system("pause");
return 0;
}
我们先不要管带有注释 what is this? 的那一行代码。
编译后执行,这次我在可执行文件.exe的目录下放了一些.c文件进行测试,看看运行结果如何:
我觉得代码意思都很明了了,然而执行结果还是失败的。
仔细观察结果,发现几个奇怪的点。
- .c文件是没问题的,统计代码行数的几行代码是由上一个版本引进的所以也应该是没问题的,但是结果却是0;
- 输出中有多余的空行。
找到问题所在了!由于fgets函数碰到'\n'是会停止输入的,\n留在了缓冲区,下一次fgets时会导致文件读取失败(个人猜想,可能有误)所以我们要设法处理掉这个'\n'。
思考一下,数组s是存储文件名的。举"C++.txt"为例,假设造成读入失败的原因是字符串后面跟了一个\n
C | + | + | . | t | x | t | \n | \0 |
---|
'\n'的位置是s[strlen(s)-1]为此我们通过如下代码进行debug
int len=strlen(s);
if(s[len-1]=='\n')
s[len-1]='\0';
再次编译运行,完成功能。此时距离成功已经很近了!
如何指定任意的文件夹路径?绝对路径!
绝对路径是什么?请看下面的代码:
FILE * fp;
fp = fopen("test.txt", "r");
我们知道fopen函数的第一个参数是一个字符串,代表文件名,这里的"test.txt"就不是绝对路径,而是当前文件夹下(也可以理解为.exe可执行程序的文件夹)的文件。如果要使用绝对路径名,就把绝对路径输入进第一个参数即可。怎么看文件夹or文件的绝对路径呢?
很简单,鼠标右键,属性,就可以看了。例如上图test的文件夹的绝对路径是E:\test
这里有一个注意点,在代码中操作字符串时,要想代表输入一个反斜杠,需要输入两个反斜杠。大家还记得转义字符吗?还有就是注意输入时要把中文输入法关掉了。
贴上比较粗略的代码,附赠注释,以及执行效果图一张:
#include<stdio.h>
#include<Windows.h>
#include<string.h>
int main()
{
char filepath[1000], batpath[1010]; //the absolute path of a file folder and a .bat file.
gets(filepath);//input absolute path of a file folder
strcpy(batpath, filepath);
strcat(batpath, "\\Text1.bat");
FILE *fp;
fp = fopen(batpath, "w");
fputs("DIR *.c /B>list.txt", fp);
fclose(fp);
system(batpath);
/*~~~the end of creating file name list~~~*/
/*~~~the beginning of get .c file name from list~~~*/
static int count = 0;
FILE *fp1, *fp2;
fp1 = fopen("list.txt", "r");
char s[100];
char singleline[1000];
while(fgets(s, 100, fp1))//get one line from list, each line refers to a .c file name
{
int len = strlen(s);
if(s[len-1] == '\n') s[len-1] = '\0';
printf("%s: ", s);
fp2 = fopen(s, "r");
/*~~~the beginning of counting lines of code~~~*/
while(fgets(singleline, 1000, fp2))//open the correct file, according to the file name
{
count++;
}
printf("%d\n", count);
fclose(fp2);
}
printf("\n");
fclose(fp1);
system("pause");
return 0;
}
由图片可以看出,我们想要的功能:输入一个文件夹的路径,统计文件夹下面的.c文件的代码行数,已经实现了。
主要的工作实现原理都在上面这段代码里,最后要做的工作就是
- 封装;
- 实现可循环输入;
- 错误信息提示;
- 考虑改改变量名、增加一点宏定义什么的,让代码更具有可读性;
- 还可以考虑添加的功能,例如可以分别显示每个文件各自的代码行数,最后显示一个总行数。
稍后我会把完成版代码推上我的github。
后记
想了想还是要感谢下栋哥的启发式教学,让我完成了一个小小的东西,虽然没啥技术含量吧,但是也是自己独立完成的,成就感还是有的。
这个问题我想了一早上,到了中午卡在绝对路径那儿,结果头晕晕的就去睡午觉了,醒来之后才解决的。233
最后,当然就是有什么错误,或者是有疑惑的地方都可以跟我说哦!
写一个程序,统计自己C语言共写了多少行代码。ver2.00的更多相关文章
- 写一个程序,统计自己C语言共写了多少行代码,Github基本操作
前言 在上一篇博客中,本人提到了自己的文件操作可以说是几乎没用过.现在想想,这也算是只在OJ上做题的一个弊端吧.虽然通过OJ做题是一个学习代码好手段,但其他方面也要多多涉猎才好,而不是说OJ用不到文件 ...
- 大一C语言学习笔记(11)---编程篇--写一个程序,可以获取从键盘上输入的的三个数,并能够判断是否可以以这三个数字作为边长来构成一个三角形,如果可以的话,输出此三角形的周长及面积,要求 0 bug;
考核内容: 写一个程序,可以获取从键盘上输入的的三个数,并能够判断是否可以以这三个数字作为边长来构成一个三角形,如果可以的话,输出此三角形的周长及面积: 答案: #include<stdio.h ...
- JAVA-集合作业-已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数
第二题 已知有十六支男子足球队参加2008 北京奥运会.写一个程序,把这16 支球队随机分为4 个组.采用List集合和随机数 2008 北京奥运会男足参赛国家: 科特迪瓦,阿根廷,澳大利亚,塞尔维亚 ...
- 迅雷笔试题 (JAVA多线程)启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC
题目:http://wenku.baidu.com/view/d66187aad1f34693daef3e8a.html 启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC. ...
- 用PHP写一个最简单的解释器Part4(写一个最简单的脚本语言)
好吧!我承认我想标题党了.大家对解释器的吸引,绝对没有自己动手写一个脚本语言更有吸引力.不过如果看到标题过来的,可能也是 我承认,之前收藏的减肥视频,我都是这样对待他们的. 不过我还是相信很多程序猿o ...
- 用C语言写一个程序,得出当前系统的整形数字长(16位,32位,64位)等,不能使用sizeof()
#include <iostream>#include <cmath>using namespace std; int main(){ int num = -1; unsign ...
- 第1讲——用C++写一个程序
一.学习新知识 在学习C++之前学过C语言了,一些基础的就不bb了,进入正题. 来几个小程序练练手: [程序1] #include <iostream> //头文件 using names ...
- 写一个程序可以对两个字符串进行测试,得知第一个字符串是否包含在第二个字符串中。如字符串”PEN”包含在字符串“INDEPENDENT”中。
package lovo.test; import java.util.Scanner; public class Java { @param args public static void main ...
- 写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示。(单词之间用空格隔开,如“Hello World My First Unit Test”)
public class Test { public void index() { String strWords = "Hello World My First Unit Test&quo ...
随机推荐
- 使用DTM ( Dynamic Topic Models )进行主题演化实验
最近想研究下Dynamic Topic Models(DTM),论文看了看,文科生的水平确实是看不懂,那就实验一下吧,正好Blei的主页上也提供了相应的C++工具, http://www.cs.pri ...
- seo步骤
1. 关键词.找trends主词.去渣渣.(扩展).(去重tool sort) .打乱 :https://adwords.google.com/https://www.google.com/trend ...
- TDK伪原创? 对matatags的研究总结
/public_html/includes/modules/meta_tags.php 46行:switch ($_GET['main_page']) {这里面包括自定义页面index.php?mai ...
- Redis(1)在windows环境下的安装和测试
初次准备使用redis,一个著名的nosql缓存数据库. 这里是第一天,就简单写一下windows下的安装,遇到的一些问题,然后简单的使用和测试,之后会在代码中使用和测试. 之后还会在生产环境中进行测 ...
- app每个页面都有一个相同的浮层控件 实现思路
可以创建一个window,设置其windowLevel为alert;
- Block 朴实理解
转载自:http://www.cnblogs.com/lzz900201/archive/2013/04/17/3025340.html block是个什么玩意儿 Block是Apple Inc.为C ...
- java.lang.RuntimeException: java.lang.NoSuchMethodException:
[java] 15/12/19 14:09:46 INFO mapred.JobClient: Task Id : attempt_201512182036_0017_m_000000_0, Stat ...
- POJ 3905 Perfect Election
2-SAT 裸题,搞之 #include<cstdio> #include<cstring> #include<cmath> #include<stack&g ...
- CSS中关于margin的理解误区
思考一 在以前,我对于margin的理解是这样的,此处用margin-top举例:指的是离相邻元素之间的距离. 但是实际是:相对于自身原来的位置偏移. 举个例子: <!DOCTYPE HTML ...
- hibetnateTemplate常用方法
一.hibetnateTemplate常用方法 1.delete(Object entity) 删除指定的持久化实例在程序中一般先用 Assert.notNull和 Assert.isTrue断 ...