项目 github 地址
一. 实现情况
基本要求
- c 统计文件字符数 (实现)
- w 统计文件词数 (实现)
- l 统计文件行数(实现)
扩展功能
- s 递归处理目录下符合条件得文件(实现)
- a 返回文件代码行 / 空行 / 注释行(实现)
高级功能
- x 图形化界面(未实现)
二. 解题思路
首先需要解析命令,取得命令变量与文件地址变量;根据命令的类型,分别对文件进行相对应的处理
基础的几个命令都是通过正则表达式或者简单的方法调用即可计算出结果
而 s 命令与其他命令不同,需要同时解析两个命令,并处理文件目录,获取符合需求的文件进行处理,与此同时还需要通过正则表达式来处理通配符。
三. 设计实现过程
代码中主要包含两个类,主体类和函数接口类
主题类包括 mian 方法,以及主要的业务逻辑代码;函数接口类用于实现模版方法模式,使得每个命令可以直接根据需要实现逻辑代码,增强了代码拓展性与减少了代码量
四. 代码说明
循环获取输入的命令,判断命令格式是否正确,是则进入命令解析方法
while (scan.hasNextLine()) {
String[] commandArray = scan.nextLine().trim().split("\\s+");
if ("wc.exe".equals(commandArray[0])) {
processFile(commandArray);
} else {
System.out.println("错误命令!");
}
}
判断是否为 s 命令,是则进入 s 命令处理方法,反之根据当前命令处理数据
static void processFile(String[] command) {
if ("-s".equals(command[1])) {
processDirectory(command);
return;
}
if (command.length > 3) {
System.out.println("错误命令!");
return;
}
if ("-c".equals(command[1])) {
calculate(command[2], (BufferedReader reader) ->
System.out.println("字符数:" + reader.lines()
.map(s -> s.replaceAll(" ", ""))
.mapToInt(String::length)
.sum())
);
} else if ("-w".equals(command[1])) {
...
} else if ("-l".equals(command[1])) {
...
} else if ("-a".equals(command[1])) {
...
} else {
System.out.println("错误命令!");
}
}
处理 s 命令时,通过 processDirectory 方法处理数据,进行通配符匹配与收集符合要求的文件地址
private static void processDirectory(String[] command) {
if (command.length < 4) {
System.out.println("错误命令!");
return;
}
String address = command[3];
//获得通配符文件名
String fileName = address.substring(address.lastIndexOf("\\") + 1);
//获得目录
File file = new File(address.substring(0, address.lastIndexOf("\\")));
//匹配通配符
Pattern p = Pattern.compile(fileName.replace(".", "\\.")
.replace("*", ".*")
.replace("?", ".?"));
//寻找当前目录以及子目录的所有文件
List filePaths = getAllFilePaths(file, new ArrayList<>());
//过滤出目标文件
filePaths = filePaths.stream()
.filter(f -> p.matcher(f.substring(f.lastIndexOf("\\") + 1)).matches())
.collect(toList());
if (!filePaths.isEmpty()) {
for (String filePath : filePaths) {
System.out.println(filePath);
processFile(new String[]{"", command[2], filePath});
}
} else {
System.out.println("符合条件的文件不存在!");
}
}
calculate 以 ProcessFile 函数接口作为参数,上层代码可以直接传入逻辑代码作为参数
private static void calculate(String fileAddress, ProcessFile processFile) {
try {
BufferedReader reader = new BufferedReader(new FileReader(fileAddress));
processFile.process(reader);
} catch (FileNotFoundException e) {
System.out.println("找不到指定的文件!");
}
}
@FunctionalInterface
interface ProcessFile {
void process(BufferedReader reader);
}
五. 测试运行
测试文件:
测试结果:
六. P2P 表格
七. 项目小结
本次项目中利用了软件工程的思想,对项目中的每一步认真考虑,考量并预计了时间,整个项目实践下来收获很多,刚开始的时候对于需求的考量不够充分,造成了代码的不断修改,希望下一次能吸取教训