用 C# 实现文件信息统计(wc)命令行程序
软件的需求分析
程序处理用户需求的模式为:
- wc.exe [parameter][filename]
在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下:
1、基本功能
- 支持 -c 统计文件字符数
- 支持 -w 统计文件单词数
- 支持 -l 统计文件总行数
2、拓展功能
- 支持 -a 返回高级选项(代码行 空行 注释行)
- 支持 -s 递归处理符合条件的文件
3、高级功能
- 支持 -x 程序以图形界面与用户交互
[filename] 是待处理文件名。
基本功能的实现
我们先来讨论基本功能的实现,在基本功能中,用户通过输入命令行的方式与程序实现交互。如 wc.exe -c -w -l D:\hello.txt 命令是实现统计 D 盘下 hello.txt 文件的字数、单词数以及总行数;而 wc.exe -l D:\hello.txt 命令是实现统计 D 盘下 hello.txt 文件的总行数;可以发现,用户每次输入的参数个数可能会是不同的,所以我们首先要做的就是从用户的输入命令中分理出命令参数和文件名。
可以用如下代码实现这一功能,在这段代码中,我们将用户输入的字符串截取成字符串数组,数组的最后一位为文件名,其他位的均为命令参数。
string message = ""; // 存储用户命令
while (message != "exit")
{
Console.Write("wc.exe ");
message = Console.ReadLine(); // 得到输入命令
string[] arrMessSplit = message.Split(' '); // 分割命令
int iMessLength = arrMessSplit.Length;
string[] sParameter = new string[iMessLength-];
// 获取命令参数数组
for (int i=; i< iMessLength-; i++)
{
sParameter[i] = arrMessSplit[i];
}
// 获取文件名
string sFilename = arrMessSplit[iMessLength - ];
}
接下来,我们新建一个类 WC 来对命令进行处理,类的基本框架如下:
public class WC
{
private string sFilename; // 文件名
private string[] sParameter; // 参数数组
private int iCharcount; // 字符数
private int iWordcount; // 单词数
private int iLinecount; // 总行数 // 参数控制信息
public void Operator(string[] sParameter, string sFilename)
{
}
// 统计基本信息:字符数 单词数 行数
private void BaseCount(string filename)
{
}
// 打印信息
private void Display()
{
}
}
在Operator()方法中,捕捉 "-c"、"-w"、"-l" 命令,通过参数素组的设置调用不同的类方法进行处理;Display()方法用来打印输出信息; BaseCount() 方法用以统计指定文件的字符数、单词数以及总行数。
我们首先填充 Operator() 方法,此方法在参数数组中包含 "-c" 或 "-w" 或 "-l" 时调用 BaseCount() 方法实现文件基本信息的统计,调用 Display() 方法打印结果。代码如下:
// 控制信息
public void Operator(string[] sParameter, string sFilename)
{
this.sParameter = sParameter;
this.sFilename = sFilename; foreach (string s in sParameter)
{
// 基本功能
else if (s == "-c" || s == "-w" || s == "-l")
{
break;
}
else
{
Console.WriteLine("参数 {0} 不存在", s);
break;
}
}
}
在 BaseCount() 中,通过传入的文件名对文件进行读取。并进行字符数、单词数、总行数的判断。判断规则如下
- 对文件进行逐字符的读取,每读取一个字符,则字符数加1
- 在读取到 '\n' 字符时,判定文件总行数加1
- 在读取到单词分割符时,判定文件单词数加1。单词分割符可以是空格,制表符和各类标点符号
// 统计基本信息:字符数 单词数 行数
private void BaseCount(string filename)
{
try
{
// 打开文件
FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(file);
int nChar;
int charcount = ;
int wordcount = ;
int linecount = ;
//定义一个字符数组
char[] symbol = { ' ', '\t', ',', '.', '?', '!', ':', ';', '\'', '\"', '\n', '{', '}', '(', ')', '+' ,'-',
'*', '='};
while ((nChar = sr.Read()) != -)
{
charcount++; // 统计字符数 foreach (char c in symbol)
{
if(nChar == (int)c)
{
wordcount++; // 统计单词数
}
}
if (nChar == '\n')
{
linecount++; // 统计行数
}
}
iCharcount = charcount;
iWordcount = wordcount + ;
iLinecount = linecount + ;
sr.Close();
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return;
}
}
接下来,我们只需要将统计信息打印出来,就完成了基本功能的实现。
// 打印信息
private void Display()
{
foreach (string s in sParameter)
{
if (s == "-c")
{
Console.WriteLine("字 符 数:{0}", iCharcount);
}
else if (s == "-w")
{
Console.WriteLine("单 词 数:{0}", iWordcount);
}
else if (s == "-l")
{
Console.WriteLine("总 行 数:{0}", iLinecount);
}
}
Console.WriteLine();
}
扩展功能的实现
在扩展功能中,用户通过输入命令行的方式与程序实现交互。并且在基本功能的基础上新增了2个命令参数;wc.exe -s -c -w D:\*.txt 实现统计 D 盘下所有文件名是txt文件的字符数与单词数的统计。wc.exe -a -c -w D:\hello.txt 实现 D 盘 hello.txt 文件 空行数、代码行数、注释行数以及字符数和单词数的统计。
在这里,我们需要扩展WC类的结构
public class WC
{
private string sFilename; // 文件名
private string[] sParameter; // 参数数组
private int iCharcount; // 字符数
private int iWordcount; // 单词数
private int iLinecount; // 行 数
private int iNullLinecount; // 空行数
private int iCodeLinecount; // 代码行数
private int iNoteLinecount; // 注释行数 // 初始化
public WC()
{
this.iCharcount = ;
this.iWordcount = ;
this.iLinecount = ;
this.iNullLinecount = ;
this.iCodeLinecount = ;
this.iNoteLinecount = ;
} // 控制信息
public void Operator(string[] sParameter, string sFilename)
{
this.sParameter = sParameter;
this.sFilename = sFilename; foreach (string s in sParameter)
{
// 遍历文件
if (s == "-s")
{
}
// 高级选项
else if (s == "-a")
{
}
// 基本功能
else if (s == "-c" || s == "-w" || s == "-l")
{
...
}
else
{
...
}
}
} // 统计基本信息:字符数 单词数 行数
private void BaseCount(string filename)
{
...
} // 统计高级信息:空行数 代码行数 注释行数
private void SuperCount(string filename)
{
}
// 打印信息
private void Display()
{
...
}
}
修改 Operator() 方法,让其能捕捉到 "-a" 命令,实现高级选项(代码行、空行、注释行的统计),代码如下:
// 高级选项
else if (s == "-a")
{
Console.WriteLine("文件名:{0}", sFilename);
SuperCount(sFilename);
BaseCount(sFilename);
Display();
break;
}
在 SuperCount() 中,通过传入的文件名对文件进行读取。进行代码行、空行、注释行的统计。判断规则如下:
- 空行:本行全为空行或是格式控制字符,若包含代码,则只有不超过一个可显示字符,如 "{";
- 注释行:本行开头除去多余空格或格式控制字符,以 ”//" 开头,或单字符+ "\\" 开头的行;
- 代码行:除去空行和注释行的其他行。
代码如下
// 统计高级信息:空行数 代码行数 注释行数
private void SuperCount(string filename)
{
try
{
// 打开文件
FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(file);
String line;
int nulllinecount = ;
int codelinecount = ;
int notelinecount = ;
while ((line = sr.ReadLine()) != null)
{
// 除去每行开头多余空格和格式控制字符
line = line.Trim(' ');
line = line.Trim('\t');
// 空行
if (line == "" || line.Length <= )
{
nulllinecount++;
}
// 注释行
else if(line.Substring(, ) == "//" || line.Substring(, ) == "//")
{
notelinecount++;
}
// 代码行
else
{
codelinecount++;
}
}
iNullLinecount = nulllinecount;
iCodeLinecount = codelinecount;
iNoteLinecount = notelinecount;
sr.Close();
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return;
}
}
再次修改 Operator() 方法,让其能捕捉到 "-s" 命令,递归处理符合条件的文件,代码如下:
// 遍历文件
if (s == "-s")
{
try
{
string[] arrPaths = sFilename.Split('\\');
int pathsLength = arrPaths.Length;
string path = ""; // 获取输入路径
for (int i = ; i < pathsLength - ; i++)
{
arrPaths[i] = arrPaths[i] + '\\'; path += arrPaths[i];
} // 获取通配符
string filename = arrPaths[pathsLength - ]; // 获取符合条件的文件名
string[] files = Directory.GetFiles(path, filename); foreach (string file in files)
{
Console.WriteLine("文件名:{0}", file);
SuperCount(file);
BaseCount(file);
Display();
}
break;
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return;
}
}
高级功能的实现
在高级功能中,用户单独输入 "-x" 参数,调用图形界面实现单个文件的选中,并输出文件信息。首先,我们修改主函数,让其可以接受单个 "-x" 命令。
static void Main(string[] args)
{
string message = ""; while (message != "exit")
{
Console.Write("wc.exe ");
// 得到输入命令
message = Console.ReadLine();
message = message.Trim(' ');
message = message.Trim('\t');
if (message != "-x")
{
// 分割命令
string[] arrMessSplit = message.Split(' ');
int iMessLength = arrMessSplit.Length;
string[] sParameter = new string[iMessLength - ];
// 获取命令参数
for (int i = ; i < iMessLength - ; i++)
{
sParameter[i] = arrMessSplit[i];
}
// 获取文件名
string sFilename = arrMessSplit[iMessLength - ];
// 新建处理类
WC newwc = new WC();
newwc.Operator(sParameter, sFilename);
}
else
{
string[] sParameter = new string[];
sParameter[] = message;
WC newwc = new WC();
newwc.Operator(sParameter, "");
}
}
}
接下来,在 Operator() 函数中增加对于 “-x" 参数的捕捉,实现调用 OpenFileDialog() 类调用文件选择对话框。
if(s == "-x")
{
string resultFile = "";
OpenFileDialog fd = new OpenFileDialog();
fd.InitialDirectory = "D:\\Patch";
fd.Filter = "All files (*.*)|*.*|txt files (*.txt)|*.txt";
fd.FilterIndex = ;
fd.RestoreDirectory = true;
if (fd.ShowDialog() == DialogResult.OK)
{
resultFile = fd.FileName;
Console.WriteLine("文件名:{0}", resultFile);
SuperCount(resultFile);
BaseCount(resultFile);
DisplayAll();
}
break;
}
注意:在主函数入口前加入 [STAThread] ,否则对话框不会显示。
class Program
{
[STAThread]
static void Main(string[] args)
{
...
}
}
最后,我们新增 DisplayAll() 函数打印全部信息
private void DisplayAll()
{
foreach (string s in sParameter)
{
Console.WriteLine("字 符 数:{0}", iCharcount);
Console.WriteLine("单 词 数:{0}", iWordcount);
Console.WriteLine("总 行 数:{0}", iLinecount);
Console.WriteLine("空 行 数:{0}", iNullLinecount);
Console.WriteLine("代码行数:{0}", iCodeLinecount);
Console.WriteLine("注释行数:{0}", iNoteLinecount);
}
Console.WriteLine();
}
至此,我们基本实现了 wc.exe 的基本功能、扩展功能和功能。
用 C# 实现文件信息统计(wc)命令行程序的更多相关文章
- wc命令行程序
软件的需求分析 程序处理用户需求的模式为: wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数与程序交互,需实现的功能如下: 1.基本功能 支持 - ...
- 软件工程第三个程序:“WC项目” —— 文件信息统计(Word Count ) 命令行程序
软件工程第三个程序:“WC项目” —— 文件信息统计(Word Count ) 命令行程序 格式:wc.exe [parameter][filename] 在[parameter]中,用户通过输入参数 ...
- MAC与windows下打开当前文件路径的命令行(终端)
MAC 下文件夹与终端: 1.打开当前路径的终端窗口方法: ①直接拖动要打开的文件夹到终端 ②打开finder的服务偏好设置, 勾选"新建位于文件夹位置的终端"选项, 以后可以在文 ...
- 用deamon打开ISO文件,提示命令行错误!!
用deamon打开ISO文件,提示命令行错误!! 解决方法:(没有关联iso文件)重新卸载deamon,再重新安装,在关联iso文件处打对勾,安装完成后即可用
- 在 Mac OS X 上创建的 .NET 命令行程序访问数据库 (使用Entity Framework 7 )
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 命令行程序增加 GUI 外壳
Conmajia © 2012 Updated on Feb. 21, 2018 命令行大家都用过: 图 1 命令行程序工作界面 现在想办法为它做一个 GUI 外壳,实际效果参考图 2. 图 2 带 ...
- myapp——自动生成小学四则运算题目的命令行程序(侯国鑫 谢嘉帆)
1.Github项目地址 https://github.com/baiyexing/myapp.git 2.功能要求 题目:实现一个自动生成小学四则运算题目的命令行程序 功能(已全部实现) 使用 -n ...
- c#词频统计命令行程序
这里将用c#写一个关于词频统计的命令行程序. 预计时间分配:输入处理3h.词条排序打印2h.测试3h. 实际时间分配:输入处理1h.词条排序打印2h.测试3h.程序改进优化6h. 下面将讲解程序的完成 ...
- Node.js 命令行程序开发资料
Node.js 命令行程序开发教程http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html用Node.js创建命令行工具ht ...
- Node: 开发命令行程序
CLI 的全称是 Command-line Interface (命令行界面),即在命令行接受用户的键盘输入并作出响应和执行的程序. 在 Node.js 中,全局安装的包一般都具有命令行界面的功能,例 ...
随机推荐
- hadoop生态搭建(3节点)-13.mongodb配置
# 13.mongodb配置_副本集_认证授权# ==================================================================安装 mongod ...
- Mac进度条卡在100%
- s3c2440系统时钟详解
一.S3C2440系统时钟体系 S3C2440的时钟控制逻辑可以外接晶振,然后通过内部电路产生时钟源:也可以直接使用内部提供的时钟源,他们通过引脚的设置来选择.时钟逻辑给整个芯片提供了3中时钟:FCL ...
- ruby配置镜像源
1.打开电脑的cmd窗口,输入如下命令即可查看gem镜像: gem sources l 或是直接使用 gem sources 查询结果如下: C:\Users\Administrator>gem ...
- openwrt从0开始-目录
终于下定决心把近期的笔记整理一下.涉及到方方面面,记录自己的成长和沉淀自己所学. 预备知识:linux, 网络通信,待补充... 目录: 前言:openwrt简介 1. openwrt源码下载及编译环 ...
- JZ2440开发板:用按键点亮LED灯(学习笔记)
本文是对韦东山嵌入式第一期学习的记录之一,如有您需要查找的信息,可以继续往下阅读. 想要用按键点亮LED灯,就需要知道按键和LED灯的相关信息,这样才可以进行之后的操作.阅读JZ2440的原理图,可以 ...
- 分享Centos6.5升级glibc过程
默认的Centos6.5 glibc版本最高为2.12, 而在进行Nodejs开发时项目所依赖的包往往需要更高版本的glibc库支持, 因此在不升级系统的前提下, 需要主动更新系统glibc库. 一般 ...
- react路由按需加载方法
使用router4之后以前的按需加载方法require.ensure 是不好使了. 所以我们改用react-loadable插件做按需加载. 第一步: yarn add react-loadable ...
- 如何在同一个Excel里,对两个很相似的工作簿比对出不同之处
如何在同一个Excel里,对两个很相似的工作簿比对出不同之处
- Sublime Text 3 新手上路:必要的安裝、設定與基本使用教學
http://blog.miniasp.com/post/2014/01/07/Useful-tool-Sublime-Text-3-Quick-Start.aspx