一.用户需求

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

  • 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. BZOJ 1085 骑士精神 迭代加深搜索+A*

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1085 题目大意: 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个 ...

  2. div宽度随屏幕大小变化

    题目: 一个页面上两个div左右铺满整个浏览器, 要保证左边的div一直为100px,右边的div跟随浏览器大小变化, 比如浏览器为500,右边div为400,浏览器为900,右边div为800. 方 ...

  3. java.util.zip.ZipException: duplicate entry(重复依赖多版本的类库)

    同步SVN仓库中的代码,更新后,运行项目,出现如下错误: com.android.build.api.transform.TransformException: java.util.zip.ZipEx ...

  4. JAVA 第三周学习总结

    20175308 2018-2019-2 <Java程序设计>第三周学习总结 教材学习内容总结 本周的学习内容为整个第四章的内容,学习中感觉知识点既多又杂,故在总结时尽量选用重要的或高度概 ...

  5. Segment Tree Beats 区间最值问题

    Segment Tree Beats 区间最值问题 线段树一类特殊技巧! 引出:CF671C Ultimate Weirdness of an Array 其实是考试题,改题的时候并不会区间取最值,区 ...

  6. RESTful API设计概要

    一.简介 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fiel ...

  7. 20155323刘威良《网络对抗》Exp9 Web安全基础

    20155323刘威良<网络对抗>Exp9 Web安全基础 实践目的 理解常用网络攻击技术的基本原理. 实践内容 Webgoat实践下相关实验. 实践过程 开启WebGoat WebGoa ...

  8. Jmeter 安装后无法启动问题

    问题:按照教程java环境安装完成,也下载了 Jmeter  安装包,但是在启动的时候 dos窗口就一直提示下面的错误信息 ‘findstr' 不是内部或外部命令,也不是可运行的程序或批处理文件.  ...

  9. WPF编程,通过DoubleAnimation控制图片的透明度,将重叠的图片依次显示。

    原文:WPF编程,通过DoubleAnimation控制图片的透明度,将重叠的图片依次显示. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307 ...

  10. 关于Trie的一些算法

    最近学习了一下关于Trie的一些姿势,感觉很实用. 终于不用每次看到字符串判重等操作就只想到hash了 关于Trie的定义,来自百度百科 在计算机科学中,Trie,又称前缀树或字典树,是一种有序树状的 ...