• 个人项目---WordCount实现(Java)


    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. 对功能的需求要考虑好后续的使用和迭代,另外要注意代码简洁性
  • 相关阅读:
    让.Net程序支持命令行启动
    拒绝卡顿——在WPF中使用多线程更新UI
    比NPOI更好用的Excel操作库——EPPlus
    利用Visual Studio Natvis 框架简化C++的变量调试工作
    使用LibZ合并.Net程序集,支持WPF
    SONY新的圈铁耳机
    找回VisualStudio异常设置中丢失的“用户未处理的(User-unhandled)”列
    去除下载文件属性中烦人的锁定状态
    POJ 3347 Kadj Squares
    POJ 1696 Space Ant(极角排序)
  • 原文地址:https://www.cnblogs.com/lyx708194/p/12546696.html
Copyright © 2020-2023  润新知