lyx708194

GitHub

一、项目简介

项目要求

wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。

实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:

wc.exe [parameter] [file_name]

功能列表

基本功能

-c file.c //返回文件 file.c 的字符数

-w file.c //返回文件 file.c 的词的数目

-l file.c //返回文件 file.c 的行数

扩展功能

-s 递归处理目录下符合条件的文件。
-a 返回更复杂的数据(代码行 / 空行 / 注释行)。

二、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 40 40
· Estimate · 估计这个任务需要多少时间 500 655
Development 开发 430 490
· Analysis · 需求分析 (包括学习新技术) 100 120
· Design Spec · 生成设计文档 30 30
· Design Review · 设计复审 (和同事审核设计文档) 20 20
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 10
· Design · 具体设计 20 25
· Coding · 具体编码 200 200
· Code Review · 代码复审 20 30
· Test · 测试(自我测试,修改代码,提交修改) 30 25
Reporting 报告 40 55
· Test Report · 测试报告 15 20
· Size Measurement · 计算工作量 10 15
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 15 20
合计 510 655

三、思路

因为之前学过Java,当即决定了实现项目所要使用的语言。因为要实现读取文件的操作,加之之前对文件io之类的使用较少,故重新去熟悉了一下Java的io流。
先从实现项目的基本功能开始,一步一步慢慢实现。其本质就是对文件的读取内容进行解析。

四、设计实现过程

根据需求对功能进行分割,一共有五个功能,分别为:

  • -c 获取字符数
  • -w 获取单词数
  • -l 获取文件行数
  • -a 获取文件空行,注释行,代码行三种数据
  • -s 递归文件目录的操作,后面需接上面四类操作数

故将其分割为五个方法,每种方法进行一种操作。

项目共有四个类,分别为:

  • Main------------------------主程序入口
  • GetFileInputStream----------对文件的io操作
  • WC---------------------------wc实体类,记录各个数据
  • WordCount-------------------各种获取方法的功能就在这个类里面

执行流程如下:


五、代码说明

文件读取操作
  • 使用缓冲流BufferedReader来读取文件效率更好
public static BufferedReader getFileInputStream(String fileName) {
        BufferedReader bufferedReader = null;
        File file = new File(fileName);
        if (file.exists()){
            try {
                bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));

            } catch (FileNotFoundException e) {
                e.printStackTrace();
                System.out.println("该路径文件不存在!");
            }
        }else{
            System.out.println("该路径或文件不存在!");
            return null;
        }
        return bufferedReader;
    }
获得文件单词数------ -w 操作
   /**
     * 获得单词数------  -w 操作
     * @param fileName 操作文件名
     * @return 返回单词数
     */
    public static int getWordCount(String fileName){
        int count1 = 0;
        BufferedReader bufferedReader01 = GetFileInputStream.getFileInputStream(fileName);
        if(bufferedReader01 == null){
            return -1;
        }
        try {
            String str = null;
            //获得每行的数据,将这一行数据分隔开存入数组中,每行数组个数相加即为单词个数
            while((str=bufferedReader01.readLine())!=null){
                String oneLine[] = str.split("\\s");
                count1+=oneLine.length;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bufferedReader01.close(); //关闭流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return count1;
    }
获得文件字符数----- -c 操作
    /**
     * 获得字符数----- -c 操作
     * @param fileName 操作文件名
     * @return 返回字符数
     */
    public static int getCharCount(String fileName){
        int count2 = 0;
        BufferedReader bufferedReader02 = GetFileInputStream.getFileInputStream(fileName);
        if(bufferedReader02 == null){
            return -1;
        }
        String str;
        try {
            //循环读取字符,直到流结束
            while((str = bufferedReader02.readLine())!=null){
                //每次读取一行后将字符串转化成字符数组,每次将字符数组的值相加即得字符的总数
                char c[] = str.toCharArray();
                count2+=c.length;
            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭流
                bufferedReader02.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return count2;
    }
获得文件行数----- -l 操作
   /**
     * 获得行数----- -l 操作
     * @param fileName 操作文件名
     * @return 返回行数
     */
    public static int getLineCount(String fileName){
        int count3 = 0;
        BufferedReader bufferedReader03 = GetFileInputStream.getFileInputStream(fileName);
        if(bufferedReader03 == null){
            return -1;
        }
        try {
            //是否有下一行
            while(bufferedReader03.readLine()!=null) {
                count3++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭流
                bufferedReader03.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return count3;
    }
获得空行、注释行、代码行----- -a 操作
    /**
     * 获得空行、注释行、代码行----- -a 操作
     * @param fileName 操作文件名
     * @return 返回wc对象,对象中包含三个复杂数据
     */
    public static WC getThreeCount(String fileName){
        BufferedReader br = GetFileInputStream.getFileInputStream(fileName);
        WC wc = new WC();
        int spaceCount = 0;
        int nodeCount = 0;
        int codeCount = 0;
        //判断是否为多行注释的标志
        boolean flag = false;
        if(br==null){
            return null;
        }
        try {
            String s1 = null;
            String s2 = null;
            while((s1=br.readLine())!=null){
                if (flag){
                    if (s1.endsWith("*/")){
                        flag = false;
                    }
                    nodeCount++;//注释行+1
                }else {
                    s2 = s1.replaceAll("\\s","");
                    if ("".equals(s2)){
                        spaceCount++;
                    }else if (s2.startsWith("//")||s2.startsWith("}//")){
                        nodeCount++;
                    }else if (s2.startsWith("/*")){
                        if (!s2.endsWith("*/")){
                            //不是单行注释,标志置为真
                            flag = true;
                        }
                        nodeCount++;
                    }else {
                        codeCount++;
                    }
                }
            }
            wc.setNodeCount(nodeCount);
            wc.setSpaceCount(spaceCount);
            wc.setCodeCount(codeCount);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭流
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return wc;
    }
遍历文件夹下所有目录,包括子目录
   /**
     * 遍历文件夹下所有目录,包括子目录
     * @param path 路径
     * @param fileList 文件列表
     */
    public static void getFileList(String path,List<String> fileList){
        File file = new File(path);
        if (file.exists()){
            if (file.isDirectory()){
                File[] files = file.listFiles();
                if (null == files||files.length == 0){
                    System.out.println("此目录为空!");
                    return ;
                }else {
                    for (File f:files) {
                        if (f.isDirectory()){
                            getFileList(f.getAbsolutePath(),fileList);
                        }else {
                            fileList.add(f.getAbsolutePath());
                        }
                    }
                }
            }else{
                System.out.println("这个不是目录路径!");
            }
        }else {
            System.out.println("此路径不存在!");
        }
    }

六、测试运行

空文件


单个字符


一个单词


一行多个单词


多行文件


代码文件(含注释)


递归目录


错误输入

七、总结

  1. 实际花费时间比预计时间多了很多,主要是在对以前学过的一些知识点没那么熟悉,需要回去查询资料加深认识
  2. 熟悉了进行一个个人项目所需要的流程和步骤,明白了要做好计划,跟着计划来执行效率会更好
  3. 一些功能还没有做好,比如文件通配符和图形化界面,后续如果有时间的话会继续去完善它
  4. 对功能的需求要考虑好后续的使用和迭代,另外要注意代码简洁性

分类:

技术点:

相关文章: