一.用户需求

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

  • 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. python第二十六课——装饰器

    装饰器是闭包的一种使用场景: python中的装饰器在定义上需要传入一个函数对象, 在此函数执行之前或者之后都可以追加其它的操作, 这样做的好处是,在不改变源码(原本业务逻辑的)同时,进行功能的扩展: ...

  2. BZOJ2115:[WC2011] Xor(线性基)

    Description Input 第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目. 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 ...

  3. Guava 的EventBus示例代码(简单笔记,后期补充)

    package guavademo.event.bus; import com.google.common.eventbus.EventBus; import com.google.common.ev ...

  4. Kafka学习之路 (四)Kafka的安装

    一.下载 下载地址: http://kafka.apache.org/downloads.html http://mirrors.hust.edu.cn/apache/ 二.安装前提(zookeepe ...

  5. Solr建立索引时,过滤HTML标签

    原文地址  http://www.joyphper.net/article/201306/188.html 1.在数据库的读取文件data-config.xml 中的entity 标记里边添加 tra ...

  6. Docker学习2-虚拟化

    虚拟化就是由位于下层的软件模块,根据上层的软件模块的期待,抽象(虚拟)出一个虚拟的软件或硬件模块,使上一层软件直接运行在这个与自己期待完全一致的虚拟环境上.从这个意义上来看,虚拟化既可以是软件层的抽象 ...

  7. 微信小程序开发 [01] 小程序基本结构和官方IDE简介

    1.小程序账户注册 实际上在进行开发时没有注册小程序账户也是可以的,官方提供的IDE提供实时编译模拟预览,和当前你有没有绑定小程序账户没有关系. 当然,最终你要正式上线你的小程序的话,肯定还是需要账户 ...

  8. Python爬虫爬取贴吧的帖子内容

    最近在看一个大神的博客,从他那里学会了很多关于python爬虫的知识,其实python如果想用在实际应用中,你需要了解许多,比如正则表达式.引入库.过滤字段等等,下面不多说,我下面的程序是爬取Ubun ...

  9. STS-使用前准备

    sts 的基础框架拿的eclipse的,你可以理解为eclipse + spring插件的高级升华版.在使用上可以很大限度的参考eclipse的操作. 首先,调整字体. 中文很麻烦的,因为编码问题.习 ...

  10. Oracle中Error while performing database login with the XXXdriver; Listener refused the connection with the following error; ORA-12505,TNS:listener does not currently know of SID given inconnect descrip

    一次连接数据库怎么也连接不上,查了多方面资料,终于找到答案,总结 首先应该保证数据库的服务启动 在myeclipse的数据库视图中点 右键->new 弹出database driver的窗口,  ...