1. 编写一个Java应用程序,实现对某个目录中的所有Java源程序文件(包含该目录的子目录中的源程序文件)进行统计。统计内容包括:
(1) 目录中每个源程序文件的总行数和空白行数,文件的字节数;
(2) 目录中所有源程序文件合计总行数、合计空白行数、合计文件的字节数。
2. 具体实现要求如下:
(1) 程序运行首先显示如下所示的菜单:
(2) 选择菜单中第1项时,要求输入一个目录名
如果输入目录名称对应的目录不存在或不是目录,则输出:
[目录名称] 不是合法的目录名称!
例如:
如果是合法存在的目录,则对该目录中的Java源程序文件进行分析,分析内容包括:
细节部分:每个源程序文件的行数、其中空行数、字节数。
合计部分:源程序文件个数、源程序文件行数、其中空行数、总的字节数。
注意,分析时包括输入目录中的所有子目录。
分析的结果的保存要求:
在当前项目目录中建立一个名为result的目录,结果文件存放在该目录中。
结果文件是一个文本文件,命名方式是用被分析的目录名作为主文件名,扩展名为目录名。
例如:分析D:demo目录,结果文件名为“demo.txt”。
结果文件中数据存放格式如下示例:
其中,
第1行:被分析目录的完整名称
第2行:空行
第3行:Files detail:
第4行:被分析目录的短名称,前面有一个 + 号
第5行:从本行开始依次输出被分析目录中的子目录和源程序文件
如果是子目录,则该行是 + 号 和 子目录的短名称
如果是源程序文件,则该行以 - 号开始,依次是:文件名、总行数、空白行数、字节数
注意:一个目录中如果既有子目录也有源程序文件,则先依次排列子目录,再依次排列文件。并且要按照名称升序排序。同时,每深入一层子目录,要缩进4个空格。
第X行:Total:
第X+1行:目录中总文件个数
第X+2行:目录中总的行数
第X+3行:目录中总的空白行数
第X+4行:目录中总字节数
(3) 选择菜单中第2项时,
如果result目录中还没有结果文件,则显示:还没有分析结果!
如果result目录中已经有结果文件,则以下面格式显示文件列表:
可以查看的结果文件有:
输入文件编号后,显示输出结果文件的内容,如果输入0表示不查看任何结果。编号输入错误应该提示。
这两天写综合性实验写的颇有感触……
emm…代码中有详细的注释,本人也比较菜,没用啥高深的算法,应该一看就会…
要是有啥不懂的可以私信问我呐
Menu类
package Project;import java.io.*;
import java.util.Scanner;public class Menu {private final Scanner Sc = new Scanner(System.in);//菜单public void showMenu() {System.out.println("----------MENU----------");System.out.println("1.分析目录中的源程序文件");System.out.println("2.查看分析结果");System.out.println("0.退出程序");System.out.println("------------------------");System.out.print("请选择:");chooseMenu();}//选择菜单的选项public void chooseMenu() {int choice;choice = Sc.nextInt();switch (choice) {case 1 -> {analyseFiles();break;}case 2 -> {checkResult();break;}case 0 -> {System.out.println("您已成功退出程序!");System.exit(0);}default -> System.out.println("您输入的选项有误!");}}//分析目录中的源程序文件private void analyseFiles() {System.out.println();System.out.print("请输入目录名称:");String FileName = Sc.next();Directory.root = new File(FileName);Directory.PathName = String.valueOf(new File(FileName));if (!Directory.root.isDirectory()) {System.out.println("错误:[" + Directory.root + "]不是目录名或不存在!\n");} else {Directory.outPut();System.out.println("分析成功!");}}private void checkResult() {System.out.println();File file = new File("Result");File[] files = file.listFiles();if (files == null) {System.out.println("还没有分析结果!");} else {System.out.println("--------------------------------");for (int i = 0; i < files.length; i++) {System.out.println(i + 1 + "." + files[i].getName());}System.out.println("--------------------------------");System.out.println("请选择要查看的结果文件(0表示放弃):");int choice = Sc.nextInt();if (choice == 0) {return;}if (choice > files.length) {System.out.print("您输入的选项有误!请重新输入:");checkResult();}System.out.println("查询结果如下:");checkFile(files[choice - 1]);//选项是比文件类数组大1的System.out.println();}}private void checkFile(File file) {BufferedReader br = null;try {br = new BufferedReader(new FileReader(file));while (true) {String data = br.readLine();if (data == null) {break;}System.out.println(data);}} catch (IOException e) {e.printStackTrace();} finally {{if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}}
}
SourceFile类
package Project;import java.io.*;public class SourceFile {private File file;private long cntOfLines;//单个源码文件的行数private long cntOfBlank;//单个源码文件的空行数private long bytes;//单个源码文件的字节数public SourceFile(File file) {this.file = file;}//统计行数public long getCntOfLines() {//只有第一次调用才进行分析统计,节约时间if (cntOfLines == 0) {getCntOfLinesAndBlank();}return cntOfLines;}//统计空行数public long getCntOfBlank() {//同上if (cntOfBlank == 0) {getCntOfLinesAndBlank();}return cntOfBlank;}//统计字节数public long getBytes() {bytes = file.length();return bytes;}//统计行数和空行数public void getCntOfLinesAndBlank() {BufferedReader br = null;try {br = new BufferedReader(new FileReader(file));while (true) {String line = br.readLine();if (line == null) {break;}cntOfLines++;//每读一行,行数加一if ("".equals(line)) {cntOfBlank++;//读到空行,空行数加一}}} catch (IOException e) {e.printStackTrace();} finally {//关闭文件if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}
}
Directory类
package Project;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;public class Directory {static File root;//待分析的文件或文件夹static String PathName;//存放root路径/*static String dataPathName = "Result";//存储分析结果文件夹的路径static String testDataPath = "testData";//存放文件或文件夹的文件夹路径static File dataDir = new File(dataPathName);//存储分析结果文件夹的文件类static File testDir = new File(testDataPath);//存放测试文件或文件夹的文件夹的文件类*/static int level = 0;//用于记录递归的层数private static long AllOfLines;private static long AllOfBlank;private static long AllOfBytes;private static class GloBal {public static ArrayList fileArrayList = new ArrayList<>();//存放待分析的.java文件public static ArrayList outputData = new ArrayList<>();//存放分析结果的String}/*private static void saveFileList() {if (root.isDirectory()) {File[] files = root.listFiles();int len = files.length;for (int i = 0; i < len; i++) {if (files[i].isDirectory()) {root = files[i];saveFileList();} else {if (files[i].getName().endsWith(".java")) {//如果以.java结尾GloBal.fileArrayList.add(files[i]);//放入ArrayList中}}}}else if(root.isFile() && root.getName().endsWith(".java")){GloBal.fileArrayList.add(root);//放入ArrayList中}}*///开头格式private static void firstShow() {GloBal.outputData.add("[" + root.getAbsolutePath() + "]" + " Result:");GloBal.outputData.add("");GloBal.outputData.add("Files detail:");}private static void saveFileList() {if (root.isDirectory()) {StringBuilder tapOfDirectory = getTap();GloBal.outputData.add(tapOfDirectory + "+" + root.getName());//目录File[] files = root.listFiles();//把root名下所有文件存进File[] files中int len = files.length;//root下文件或文件夹的个数//flag判断递归层数是否相同int flag = 0;for (int i = 0; i < len; i++) {//循环if (files[i].isDirectory()) {//如果是一个目录root = files[i];//更新root路径//递归层数相同时level只需要加一次if (flag == 0) {level++;flag = 1;}saveFileList();//递归 以存储.java文件} else {//如果不是一个目录(即是一个文件)if (files[i].getName().endsWith(".java")) {//如果以.java结尾//感觉好像没必要放进ArrayList//好吧好像有用,可以统计.java文件个数GloBal.fileArrayList.add(files[i]);//放入ArrayList中SourceFile SF = new SourceFile(files[i]);//使用SourceFile类进行统计//处理文件名 方面后面对齐StringBuilder newName = tidyFileName(files[i]);//处理Total,方便Blank对齐StringBuilder newTotal = tidyLines(files[i]);//处理Blank,方便bytes对齐StringBuilder newBlank = tidyBlank(files[i]);//字符数long bytes = SF.getBytes();StringBuilder tapOfFiles = getTap();GloBal.outputData.add(tapOfFiles+ " -" + newName+ "\tTotal: " + newTotal+ "Blank: " + newBlank+ bytes + " bytes");/*GloBal.outputData.add(" -" + files[i].getName()+"\t\tTotal: " + SF.getCntOfLines()+ ", Blank: " + SF.getCntOfBlank()+ ", " + SF.getBytes() + " bytes");*///统计AllOfLines += SF.getCntOfLines();AllOfBlank += SF.getCntOfBlank();AllOfBytes += SF.getBytes();}}}} else if (root.isFile() && root.getName().endsWith(".java")) {//如果是文件且为.java文件则直接存储GloBal.fileArrayList.add(root);SourceFile SF = new SourceFile(root);StringBuilder newName = tidyFileName(root);StringBuilder newLines = tidyLines(root);StringBuilder newBlank = tidyBlank(root);GloBal.outputData.add(" -" + newName+ "\t Total: " + newLines+ "Blank: " + newBlank+ SF.getBytes() + " bytes");//统计AllOfLines += SF.getCntOfLines();AllOfBlank += SF.getCntOfBlank();AllOfBytes += SF.getBytes();}}//子目录比上一级缩进4格private static StringBuilder getTap() {StringBuilder tap = new StringBuilder();for (int i = 1; i <= level * 4; i++) {tap.append(" ");}return tap;}private static void saveTotal() {StringBuilder newCntOfFiles = tidyTotal(new StringBuilder(String.valueOf(getAllOfFiles())));StringBuilder newCntOfLines = tidyTotal(new StringBuilder(String.valueOf(getAllOfLines())));StringBuilder newCntOfBlank = tidyTotal(new StringBuilder(String.valueOf(getAllOfBlank())));StringBuilder newCntOfBytes = tidyTotal(new StringBuilder(String.valueOf(getAllOfBytes())));GloBal.outputData.add("Total:");GloBal.outputData.add("\t\t" + newCntOfFiles + "\tJava Files");GloBal.outputData.add("\t\t" + newCntOfLines + "\tlines in files");GloBal.outputData.add("\t\t" + newCntOfBlank + "\tblank lines");GloBal.outputData.add("\t\t" + newCntOfBytes + "\tbytes");}private static StringBuilder tidyTotal(StringBuilder str) {for (int i = str.length(); i < 8; i++) {str.append(" ");}return str;}private static StringBuilder tidyFileName(File file) {//处理文件名 方面后面对齐StringBuilder newName = new StringBuilder(file.getName());int size = file.getName().length();for (int j = size; j < 40; j++) {newName.append(" ");}return newName;}private static StringBuilder tidyLines(File file) {SourceFile SF = new SourceFile(file);//使用SourceFile类进行统计StringBuilder newLines = new StringBuilder(String.valueOf(SF.getCntOfLines()));int len = newLines.length();for (int j = len; j < 6; j++) {if (j == len) {newLines.append(",");}newLines.append(" ");}return newLines;}private static StringBuilder tidyBlank(File file) {SourceFile SF = new SourceFile(file);//使用SourceFile类进行统计StringBuilder newBlank = new StringBuilder(String.valueOf(SF.getCntOfBlank()));int lengthOfBlank = newBlank.length();for (int j = lengthOfBlank; j < 6; j++) {if (j == lengthOfBlank) {newBlank.append(",");}newBlank.append(" ");}return newBlank;}//对文件进行排序//这个可能有问题,后续要注意调试//如果一个目录里既有子目录又有文件,则先排子目录,再排文件private static void sortFiles(File[] files) {//使用匿名内部类构造比较器,对文件进行排序Arrays.sort(files, new Comparator() {@Overridepublic int compare(File o1, File o2) {if (o1.isFile() && o2.isFile()) {//都是文件return o1.getName().compareTo(o2.getName());} else if (o1.isDirectory() && o2.isDirectory()) {//都是目录return o1.getName().compareTo(o2.getName());} else if (o1.isDirectory() && o2.isFile()) {//一个目录一个文件return -1;} else if (o1.isFile() && o2.isDirectory()) {//一个文件一个目录return 1;} else {return 0;}}});}//统计.java文件个数public static int getAllOfFiles() {return GloBal.fileArrayList.size();}//统计所有.java文件中的字符个数/*private static void CountOfCharOfFile() {long SumOfChar = 0;for (int i = 0; i < GloBal.fileArrayList.size(); i++) {SumOfChar += GloBal.fileArrayList.get(i).length();}}*///统计总行数public static long getAllOfLines() {return AllOfLines;}//统计空行数public static long getAllOfBlank() {return AllOfBlank;}//统计字符数public static long getAllOfBytes() {return AllOfBytes;}/** 把分析结果保存到项目目录下的result文件夹* */public static void saveAnalyzeData() throws IOException {root = new File(PathName);//原输入的目录名称,在saveFileList经过递归后root不再是一开始的root了File resultFile = new File("Result");if (!resultFile.exists()) {resultFile.mkdir();}BufferedWriter AnalyzeDataIn = new BufferedWriter(new FileWriter(resultFile + "\\" + root.getName() + ".txt"));for (int i = 0; i < GloBal.outputData.size(); i++) {AnalyzeDataIn.write(GloBal.outputData.get(i));AnalyzeDataIn.newLine();}AnalyzeDataIn.flush();}/** 运行各方法以分析文件* 保存分析数据* */public static void outPut() {firstShow();saveFileList();saveTotal();try {saveAnalyzeData();} catch (IOException e) {e.printStackTrace();}}
}
Main类
package Project;public class Main {public static void main(String[] args) {run();}public static void run(){Menu menu = new Menu();menu.showMenu();run();}
}