一.用户需求

程序处理用户需求的模式为:

  • wc.exe [parameter][filename]

在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下:

1、基本功能

  • 支持 -c  统计文件字符数
  • 支持 -w 统计文件单词数
  • 支持 -l  统计文件总行数

2、拓展功能

  • 支持 -a 返回高级选项(代码行 空行 注释行)
  • 支持 -s 递归处理符合条件的文件

二.功能实现

  为了增加程序的可读性,我对各项功能进行了模块化。共写了六个子函数。其中void charcount(FILE *fp)用于统计文件中字符的数量,void wordcount(FILE *fp)用于统计文件中单词的数量,void linecount(FILE *fp)用于统计文件的行数,void mixline(FILE *fp)实现统计文件中的代码行,注释行,空行的数量,void multi_file(char *path,char *func)用于处理文件目录下的多个文件void filesearch(char *path, int layer,char *func,char *q)递归处理目录下符合条件的文件。首先应当把用户输入的字符串读到数组string[100]中,然后对字符串进行处理,分离出功能选项和文件路径。然后分别存储在function[20]和file[100]中,使用for循环结构以及switch分支语句对用户要求的各项功能进行实现。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <io.h> void charcount(FILE *fp); //统计文件中的字符数量
void wordcount(FILE *fp); //统计文件中的单词数量
void linecount(FILE *fp); //统计文件行数
void mixline(FILE *fp); //统计文件中的代码行,注释行,空行的数量
void multi_file(char *path,char *func); //处理文件目录下的多个文件
void filesearch(char *path, int layer,char *func,char *q); //递归处理目录下符合条件的文件 int main()
{ int i,j,flag=;
FILE *fp;
char file[],string[],function[];
while()
{
if(flag==)
printf("\n");
printf("wc.exe ");
flag=;
gets(string);
for(i=,j=;string[i]!='\0';i++)
{
if(string[i]=='-'&&islower(string[i+])) //islower(char a)用于判断字符是否是字母
{
function[j]=string[i+];
j++;
if(string[i+]!=' ')
{
printf("Input is wrong!");
exit();
}
i+=;
}
if(i!=&&string[i+]!='-')
{
i++;
break;
}
}
function[j]='\0';
j=;
while(string[i]!='\0')
{
file[j]=string[i];
i++;
j++;
}
file[j]='\0';
if(function[]!='s')
{
if((fp=fopen(file,"r"))==NULL) //读取文件内容
{
printf("The file is not found!\n");
exit();
}
} for(i=;function[i]!='\0';i++)
{
switch(function[i])
{
case 'c': charcount(fp); break;
case 'w': wordcount(fp); break;
case 'l': linecount(fp); break;
case 'a': mixline(fp); break;
case 's': multi_file(file,function); break;
default:
{
printf("Input is wrong!");
break;
}
}
if(function[]=='s')
break;
}
}
return ;
}

  用户操作-c:void charcount(FILE *fp)可以统计打开的文件中的字符数(除掉“\n”),遇到换行符不会进行统计,feof(fp)用于判断文件指针是否指向了文件的末尾,到了文件末尾则跳出循环。在完成打印操作后,要使用rewind(fp)使文件指针指向文件的开头,以便于其它子函数对文件进行操作。

void charcount(FILE *fp)
{
char sign;
int charnum=;
do{
sign=fgetc(fp);
if((feof(fp)))
break;
else if(sign=='\n'){}
else
charnum++;
}
while();
printf("Number of characters:%d\n",charnum);
rewind(fp); //进行完操作后使文件指针指向文件头 }

  用户操作-w:void wordcount(FILE *fp)实现对单词数的统计(我所定义的单词是以字母或下划线开头的由字母,数字,下划线构成的符号串)。其中使用到了isalpha(char sign),isalnum(char sign),这两个函数均包含在了ctype.h的头文件中,分别用于识别字母,字母和数字。库函数应用可以减少代码量。

void wordcount(FILE *fp)
{
int i=;
char sign;
do{
sign=fgetc(fp);
if((feof(fp)))
break;
if((unsigned char)isalpha(sign)||(int)sign==)
{
while((unsigned char)isalnum(sign)||(int)sign==)
sign=fgetc(fp);
i++;
}
}
while();
printf("Number of words:%d\n",i);
rewind(fp);
}

  用户操作-l:void linecount(FILE *fp)可以统计文件中的行数。主要是通过判断换行符来计数。

void linecount(FILE *fp)
{
int line=;
char sign;
sign=fgetc(fp);
if(sign!=NULL)
line=;
do{
sign=fgetc(fp);
if((feof(fp))) //判断是否到了文件尾
break;
if(sign=='\n')
{
sign=fgetc(fp);
if(sign!=NULL&&sign!='\n')
line++;
}
}
while();
printf("Number of rows:%d\n",line);
rewind(fp);
}

  用户操作-a:void mixline(FILE *FP)实现统计文件中的代码行,注释行,空行的数量。

  空行:本行全部是空格或者格式控制字符,如果包括代码,则只有不超过一个可显示字符,例如“}”。

  代码行:本行包括多于一个字符的代码。

  注释行:本行不是代码行,并且本行包括注释,"}//注释”这种情况也属于注释行。

  利用分支结构对各种情况进行判断,其中fseek(fp,-1,1)的作用是回退一个字符,这样改变文件指针的位置的方法即实现可不使用字符串保存字符来进行判断。

void mixline(FILE *fp)
{
int i=,blankline=,codeline=,noteline=;
char sign;
do{
if(feof(fp))
break;
sign=fgetc(fp);
if((feof(fp)))
break;
while(sign=='\t'||sign==' ')
sign=fgetc(fp);
if(sign=='\n')
{
sign=fgetc(fp);
i=;
while(sign=='\t'||sign==' ')
sign=fgetc(fp);
if(sign=='\n')
{
blankline++;
i=;
}
else if(sign=='}'||sign=='{')
{
sign=fgetc(fp);
while(sign=='\t'||sign==' ')
{
sign=fgetc(fp);
i++;
}
if(sign=='\n')
{
blankline++;
i=;
}
else if((feof(fp)))
blankline++;
else
{
fseek(fp,-i,);
i=;
}
}
else
fseek(fp,-,); //fseek()函数可以对文件指针进行操作,使指针向前或向后
}
else if(sign=='}'||sign=='/')
{
sign=fgetc(fp);
while(sign==' '||sign=='\t')
sign=fgetc(fp);
if(sign=='/'||sign=='*')
{
noteline++;
while(sign!='\n')
{
sign=fgetc(fp);
if(feof(fp))
break;
}
if(!(feof(fp)))
fseek(fp,-,);
}
}
else
{
codeline++;
while(sign!='\n')
sign=fgetc(fp);
fseek(fp,-,);
} }
while();
printf("Number of blank lines: %d\n",blankline);
printf("Number of code lines: %d\n",codeline);
printf("Number of comment lines: %d\n",noteline);
rewind(fp);
}

  用户操作-s:void multi_file(char *path,char *func)用于把文件路径和文件的后缀名分离,分别保存在两个数组中。然后调用void filesearch(char *path, int layer,char *func,char *q),实现对文件的递归处理。void filesearch(char *path, int layer,char *func,char *q)中的结构体_finddata_t,包含在io.h头文件中。

  struct _finddata_t   

  {

     unsigned attrib;              //文件属性

      time_t time_create;              //创建时间

          time_t time_access;              //文件最后一次被访问时间按

time_t time_write;                 //文件最后一次被修改时间

_fsize_t size;                            //文件大小

char name[_MAX_FNAME]; //文件名

 };

  unsigned atrrib:文 件属性的存储位置。它存储一个unsigned单元,用于表示文件的属性。文件属性是用位表示的,主要有以下一些:_A_ARCH(存档)、 _A_HIDDEN(隐藏)、_A_NORMAL(正常)、_A_RDONLY(只读)、_A_SUBDIR(文件夹)、_A_SYSTEM(系统)。_findfirst(curr, &filefind))用于搜索与指定的文件名称匹配的第一个实例,若成功则返回第一个实例的句柄,否则返回-1L,_findnext(handle, &filefind)搜索与_findfirst函数提供的文件名称匹配的下一个实例,若成功则返回0,否则返回-1。递归调用可以实现若目录下存在文件夹,则可以进入文件夹继续搜索相应后缀名的文件。

void multi_file(char *path,char *func)
{
int i,j=;
char p[],q[];
for(i=;path[i+]!='*';i++)
{
if(path[i]=='\0')
{
printf("Input is wrong!");
exit();
}
p[i]=path[i];
}
p[i]='\0';
for(i=i+;path[i]!='\0';i++,j++)
q[j]=path[i];
q[j]='\0';
filesearch(p, ,func,q);
}

void filesearch(char *path, int layer,char *func,char *q)
{
struct _finddata_t filefind;
char curr[],path1[];
int done = ,handle,i,flag=,j;
FILE *fp;
strcpy(path1,path);
strcpy(curr,path1);
strcat(curr,"\\");
strcat(curr,q);
if((handle = _findfirst(curr, &filefind)) != -)
{
if(handle>)
done=;
else
done=-;
while(!done)
{
if(!(strcmp(filefind.name,".")))
done = _findnext(handle, &filefind);
if(flag==)
done = _findnext(handle, &filefind);
if(done==-)
break;
if(strcmp(filefind.name, "..") == )
{
flag=;
continue;
}
if((_A_SUBDIR == filefind.attrib)) // 判断是否是文件夹
{
flag=;
strcat(path1,"\\");
strcat(path1,filefind.name);
filesearch(path1, layer+,func,q); // 递归遍历子目录
strcpy(path1,path);
}
else
{
flag=;
strcat(path1,"\\");
strcat(path1,filefind.name);
if((fp=fopen(path1,"r"))==NULL) //读取文件内容
{
printf("The file is not found!\n");
exit();
}
printf("The file path:%s\n",path1);
strcpy(path1,path);
for(i=;func[i]!='\0';i++)
{
if(func[i]=='s')
continue;
switch(func[i])
{
case 'c': charcount(fp); break;
case 'w': wordcount(fp); break;
case 'l': linecount(fp); break;
case 'a': mixline(fp); break;
default:
{
printf("Input is wrong!");
break;
}
}
}
}
}
_findclose(handle);
}
}

三. 运行结果

1、基本功能支持

    -c  统计文件字符数支持

    -w 统计文件单词数支持

    -l  统计文件总行数

实现对本地文件的操作

2、拓展功能支持

    -a 返回高级选项(代码行 空行 注释行)支持

    -s 递归处理符合条件的文件

文件路径如下图:E:\a

E:\a\文件

实现对E:\a中的所有类型文件以及子文件夹中的文件操作

实现对E:\a中后缀名为.cpp的文件的操作

   至此,wc.exe的基本功能以及扩展功能就已经实现了,在编程的过程中确实学习到了很多知识,网络中有资源宝库,能得到自己需要的东西。可能程序还有地方不完善,希望老师以及同学们多多指教。

(第三周)wc.exe—命令行实现对指定目录下文件的操作的更多相关文章

  1. 如何用DOS命令,获取一个目录下的文件数目

    发信人: GOOGOODALLS (我爱Figo), 信区: DOS 标  题: 如何用DOS命令,获取一个目录下的文件数目? 发信站: 水木社区 (Fri Mar  9 08:40:01 2007) ...

  2. DOS命令行(1)——Windows目录与文件应用操作

    cd 1.使用cd快速切换到指定盘符与目录中 命令格式1:cd [/d] [<盘符>][<路径>] 或 chdir [/d] [<盘符>][<路径>] ...

  3. Linux常用基础命令整理:关机命令、查看目录下文件命令等

    Linux常用基础命令整理:关机命令.查看目录下文件命令等 整理了一些Linux常用基础命令,欢迎指正. 首先记住四个热键,学会这四个键,收益一辈子. Tab按键---命令补齐功能Ctrl+c按键-- ...

  4. 查看 /var/log目录下文件个数 命令tree 、cut

    查看 /var/log目录下文件个数 方法1. [root@oldboy learn_shell]# tree -L 1 /var/log/ |tail -1 5 directories, 42 fi ...

  5. find命令查找包含指定内容的文件

    find / | xargs grep function 查找系统根目录下面的所有文件的内容中包含有function字符串的文件列表. find .|xargs grep xfind . -exec ...

  6. 用bash命令得到Windows一个目录下的所有文件并且把结果输入到一个文件

    方式一: 只用如下一条语句就可以了: tree/f>index.txt 放入一个文件中命名为"****.bat" 双击就会在该目录下生成一个index.txt文件,在这个文件 ...

  7. 命令行保存指定目录文件的名字(可包含文件夹文字)到txt文本文件

    Microsoft Visual Studio中配置OpenCV解决方案属性的时候, 需要将OpenCV的lib扩展名的库文件添加到属性的依赖列表里面,网上的有些人博客里面直接给出的会有问题(但大多数 ...

  8. linux 统计命令执行后的行数或者统计目录下文件数目

    ls |wc 是统计你这个目录下的文件数目.ls |wc -l是输出第一个结果即31即文件的数目.

  9. 运行cmd直接进入指定目录下的命令

    新建一个.bat批处理文件,文件命令为@ECHO OFF cmd /k cd /d c:data 运行该批处理文件cmd就可进入指定的文件夹,感兴趣的朋友可以参考下啊 新建一个.bat批处理文件,文件 ...

随机推荐

  1. html5式程序员表白

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/whqet/article/details/26394493 前端开发whqet,csdn,王海庆,w ...

  2. 哪些地方会出现css阻塞,哪些地方会出现js阻塞?

    Js的阻塞特性: 所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等.直到JS下载.解析.执行完毕后才开始继续并行下载其他资源并呈现内容.为了提高用户体验,新一代浏览器 ...

  3. Docker技术入门与实战 第二版-学习笔记-9-Docker Compose 项目-3-Django项目实例

    使用 Django 我们现在将使用 Compose 配置并运行一个 Django/PostgreSQL 应用.在此之前,先确保 Compose 已经安装. 1.通过编辑 Dockerfile文件来指定 ...

  4. Java之时间转换

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse( ...

  5. WorldWind源码剖析系列:下载队列类DownloadQueue

    下载队列类DownloadQueue代表具有优先级的下载队列,该类的存储下载请求的数组链表专门按一定的优先级来存储下载请求的.该类的类图如下. 下载队列类DownloadQueue各个字段的含义说明如 ...

  6. android java.lang.StackOverflowError

    转自:http://hi.baidu.com/424660053/item/bee53a2633870dccddf69a17 最近做项目出现一个java.lang.StackOverflowError ...

  7. ansible-playbook如何判断并中断执行

    - fail: msg="Bailing out. this play requires 'bar'"       when: bar is not defined 我的需求是当某 ...

  8. 计算机视觉-sift(2)代码理解

    之前结合不同人的资料理解了sift的原理,这里通过opencv中的代码来加深对sift的实现的理解. 使得能够从原理性理解到源码级的理解.不过该博文还是大量基于<赵春江, opencv2.4.9 ...

  9. MVC bundle的使用总结

    在我们的项目里面充斥着很多静态文件,为了追求模块化.插件化很多静态文件都被设计成模块的方式或者被分解,在需要的时候在通过组合的方式在UI层上使用:这就带来一个问题,文件多了会影响浏览器加载页面的速度, ...

  10. 关于CAN总线的被动错误标志的问题?

    关于CAN总线的被动错误标志的问题? 关于CAN总线的被动错误标志,协议中的描述是"处于被动错误状态的单元检测出错误时,输出被动错误标志". 对此有几个疑问: 1.被动错误标志的发 ...