SCAU 2022 Java综合性实验

目录

实验要求

思路讲解

程序类图

代码实现


如果你觉得这篇文章帮到你的话,可以点个赞,这是对作者最好的鼓励

实验要求

一、实验目的

1.掌握面向对象程序设计的基本方法

2.应用Java语言编写应用程序

二、实验要求:

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表示不查看任何结果。编号输入错误应该提示。

3. 可以使用给定目录进行测试,点击下载(需要华农校园网,具体文件在文末) 测试用目录的压缩包,该目录分析的结果应该如下图:


思路讲解

首先分析题目要求:

  1. 两个菜单:主菜单以及查看分析结果时的文件列表
  2. 分析过程:对于源码文件,统计空行数,总行数以及字节数;对于目录文件,排序后递归统计子目录及该目录下所有源码文件总空行数,总行数以及总字节数;最后保存到Result目录的文件
  3. 查看结果:查看Result的文件列表,而后选择查看文件并输出到控制台

几个主要方法思路介绍:

  1. 菜单直接输出即可,选项的实现可以用 if-else 也可以用 switch-case
  2. 源码文件也是字符文件的一种,通过 BufferedReader 中的 readLine 方法从单个.java文件中一行一行循环读取数据,统计空行数,总行数,字节数
  3. 目录文件需要用深度优先搜索算法,也就是递归,终止条件为找到一个 .java 文件并调用方法 2,循环条件为找到一个目录,递归调用自身
  4. 保存到文件,本猿用的是 System.setOut 的重定向方法,方便直接输出到文件中
  5. 读取结果文件与方法 2 的读取源码文件相同

程序类图


代码实现

一、Main 类

//Main类
import View.Menu;

public class Main {
	public static void main(String[] args){
		Menu menu = new Menu();
		menu.showMenu();
		System.out.println("程序结束");
	}
}

二、Menu 类

//Menu 类
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

import element.Directory;

public class Menu {
	private Scanner scan = 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("请选择:");
		chooseFunction();
	}
    
    //选择执行的操作
	private void chooseFunction() {
		int type = scan.nextInt();
		if (type == 1)
			analyseSrcFiles();//调用下文私有方法
		else if (type == 2)
			checkResult();//调用下文私有方法
		if(type == 1 || type == 2)
			showMenu();
	}
    
    //操作1
	private void analyseSrcFiles() {
		System.out.println();
		System.out.print("输入目录名称:");
		String dirName = scan.next();
        
        //指定分析目录
		File dir = new File(dirName);
		Directory directory = new Directory(dir);
		if(!dir.isDirectory()){
			System.out.println("错误:["+dirName+"]不是目录名或不存在!\n");
		}else{
			//调用directory 类 analyseSubDir 方法
            directory.analyseSubDir();
			System.out.println("分析完成\n");
		}
	}
	
	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.print("选择要查看的结果文件(0表示放弃):");
			int type = scan.nextInt();
			if(type == 0)
				return;
            
            //下标 = 序号 - 1
			checkFile(files[type-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) {
            //eclipse自动生成的异常处理
			e.printStackTrace();
		} finally{
            //关闭输入流,避免发生其他错误
			if(br != null){//确保下文close不会访问空指针
				try {
					br.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}			
			}
		}
	}
}

三、SourceFile 类

//SourceFile 类
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class SourceFile {
	private File file;
	private long numOfLines;//单个源码文件行数
	private long numOfBlank;//单个源码文件空行数
	private long bytes;//单个源码文件字节数
	
    //参数为源码文件
	public SourceFile(File file){
		this.file = file;
		bytes = file.length();
	}
	
	private void getNumOfLinesAndBlank(){
        //文件操作原理同 Menu 类
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(file));
			
            //从源码文件中读取每一行
            while(true){
				String line = br.readLine();
				if (line == null) //文件读取结束
					break;
				numOfLines++; //每读一行,总行数加一
				if("".equals(line)){ //读到空行
					numOfBlank++;
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public long getNumOfLines(){
		if(numOfLines == 0) //第一次调用计算后返回,下次无需计算直接返回
			getNumOfLinesAndBlank();
		return numOfLines;
	}
	public long getNumOfBlank(){
		if(numOfBlank == 0)//第一次调用计算后返回,下次无需计算直接返回
			getNumOfLinesAndBlank();
		return numOfBlank;
	}
	public long getBytes(){
		return bytes;
	}
}

四、Directory 类

//Directory 类
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Comparator;

public class Directory {
	private File directory;
	private long numOfSrcFile;//该目录下所有文件数
	private long sumLines;//所有源码文件总行数
	private long sumBlank;//所有源码文件总空行数
	private long sumBytes;//所有源码文件总字节数

    //形参为菜单中输入的目录,非法目录已被 Menu 处理,该 File 必为合法
	public Directory(File dir) {
		directory = dir;
	}
	

	private void changeOut(){
		File content = new File("Result");//相对当前Project的路径,与src同级
		content.mkdir();//生成目录文件夹
		File resultTxt = new File("Result\\"+directory.getName() + ".txt");
		try {
			resultTxt.createNewFile();//生成保存 result 的文件
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
            //从控制台重定向输出到文件中
			PrintStream ps = new PrintStream(resultTxt);
			System.setOut(ps);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void analyseSubDir() {
        //提前保存控制台,输出到文件完毕后恢复输出到控制台
		PrintStream out = System.out;
		changeOut();
		System.out.println("[" + directory.getAbsolutePath() + "] Result:\n\nFiles detail:");
		dfsAnalyse(directory, 0);//递归统计目录下每个源码文件数据
		System.out.println("Total:");
		System.out.printf("\t%5d Java Files\n\t%5d lines in files\n\t%5d blank lines\n\t%5d bytes", numOfSrcFile,
				sumLines, sumBlank, sumBytes);
		System.setOut(out);//恢复输出到控制台
	}

    //判断文件是否为源码文件
	private boolean isJava(File file) {
		String name = file.getName();
		int len = name.length();
		String postName = (String) name.subSequence(len - 5, len);//参数区间左闭右开,获取文件名后五个字母形成的子串
		// System.out.println(postName);
		return ".java".equals(postName);
	}

	private void sortFiles(File[] files) {
        //匿名内部类构造比较器,对目录下文件排序
		Arrays.sort(files, new Comparator<File>() {

			@Override
			public 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;//理论上不会走到这里,为了确保返回值为 int,编译不报错
				}
			}

		});
	}

    //File形参为当前递归的文件,level为递归的层数,也是缩进的倍数
	private void dfsAnalyse(File file, int level) {
		for (int i = 0; i < level; ++i)
			System.out.print("    ");
		if (file.isDirectory()) {//递归到目录继续递归
			System.out.println("+" + file.getName());
			File[] files = file.listFiles();
			sortFiles(files);
			for (int i = 0; i < files.length; ++i) {
				dfsAnalyse(files[i], level + 1);
			}
		} else if (isJava(file)) {//递归文件统计信息并输出
			// System.out.println("isJava: " + isJava(file));
			System.out.print("-" + file.getName());
			SourceFile srcFile = new SourceFile(file);
			numOfSrcFile++;
			sumBlank += srcFile.getNumOfBlank();
			sumLines += srcFile.getNumOfLines();
			sumBytes += srcFile.getBytes();
			int spaceLength = file.getName().length();
			for (int i = spaceLength; i < 35; ++i) {//对齐,为了方便没有统计最长的文件名,随便写了个35
				System.out.print(" ");
			}
			System.out.println("\tTotal:\t" + String.format("%5d", srcFile.getNumOfLines()) + ", Blank:\t"
					+ String.format("%5d", srcFile.getNumOfBlank()) + ",\t" + String.format("%5d", srcFile.getBytes())
					+ " Bytes");
		}
	}
}
  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实验5学生成绩分析程序 实验类型:综合性 实验目的:综合运用Java语言和面向对象技术开发一个小型软件系统 实验内容: 1. 已经提供的原始数据:班级成绩单文件 该文件为文本文件,存储某个班的所有学生某门课程的成绩。 例如:2012级计算机科学与技术8班-面向对象程序设计.txt 文件中每行存储一个学生的成绩,包括:学号、姓名和成绩,中间用英文逗号分隔。 说明:学号和姓名是字符串,成绩使用整数。 例如“2012级计算机科学与技术8班-面向对象程序设计.txt”文件中存放该班学生面向对象程序设计的考试成绩。内容为: 201230740801,赵一,68 201230740802,钱二,82 201230740803,孙三,58 201230740804,李四,62 201230740805,冯五,73 …… 2. 实验要求: (1) 程序使用图形用户界面。 (2) 文件操作与数据统计功能 打开上面给出的文本文件,将其中的成绩数据加载到内存。 把内存中的成绩数据另存为格式相同的另一个文本文件。 把内存中的成绩数据另存为一个二进制的对象文件。 打开已经保存的二进制的对象文件,将其中的成绩数据加载到内存。 统计分析已经加载到内存的班级的成绩,包括:最高分、最低分、平均分、各成绩等级的人数和百分比。 说明:该部分界面参见图1,黄色注释框标出的是完成本部分功能需要的界面。 (3) 图形统计功能 对加载到内存的成绩单进行“柱形图”分析 对加载到内存的成绩单进行“饼图”分析 说明:该部分界面参见图2,图1红注释框标出的是完成本部分功能需要的按钮。图形使用Java的Graphics对象绘制,不得使用第三方类库。 (4) 查询排序功能 在“查询输入框”输入“学号、姓名或成绩”的全部或部分,成绩列表中只显示包括输入数据的成绩项目。 点击表格的“列标题”,可以自动按该列排序,2次点击可以切换“升序”和“降序”。 说明:图1黑色注释框指出的是查询界面的位置。提示:JTabel的RowSorter。 提交要求: 1. 打包为可以执行的JAR文档,其中要包含源程序文件。 2.实验报告,简要说明程序的设计思路,不要贴代码,不超过5页(含封面)WORD文档,扩展名为.DOC。 成绩评定说明: 1. 前4个实验随堂练习的平均成绩占实验课最终成绩的70%。 2. 综合性实验满分100分,占实验课最终成绩的70%。 3. 综合性实验评分细则 (1) 完成实验要求的前2项,75分----80分 (2) 完成实验要求的前4项,85分----90分 (3) 完成实验要求全部4项,95分----100分 说明:确定分数段后,根据完成的程序结构、运行效率、界面美观等给出具体分数。
实验5学生成绩分析程序 实验类型:综合性 实验目的:综合运用Java语言和面向对象技术开发一个小型软件系统 实验内容: 1. 已经提供的原始数据:班级成绩单文件 该文件为文本文件,存储某个班的所有学生某门课程的成绩。 例如:2012级计算机科学与技术8班-面向对象程序设计.txt 文件中每行存储一个学生的成绩,包括:学号、姓名和成绩,中间用英文逗号分隔。 说明:学号和姓名是字符串,成绩使用整数。 例如“2012级计算机科学与技术8班-面向对象程序设计.txt”文件中存放该班学生面向对象程序设计的考试成绩。内容为: 201230740801,赵一,68 201230740802,钱二,82 201230740803,孙三,58 201230740804,李四,62 201230740805,冯五,73 …… 2. 实验要求: (1) 程序使用图形用户界面。 (2) 文件操作与数据统计功能 <1> 打开上面给出的文本文件,将其中的成绩数据加载到内存。 <2> 把内存中的成绩数据另存为格式相同的另一个文本文件。 <3> 把内存中的成绩数据另存为一个二进制的对象文件。 <4> 打开已经保存的二进制的对象文件,将其中的成绩数据加载到内存。 <5> 统计分析已经加载到内存的班级的成绩,包括:最高分、最低分、平均分、各成绩等级的人数和百分比。 说明:该部分界面参见图1,黄色注释框标出的是完成本部分功能需要的界面。 (3) 图形统计功能 <1> 对加载到内存的成绩单进行“柱形图”分析 <2> 对加载到内存的成绩单进行“饼图”分析 说明:该部分界面参见图2,图1红注释框标出的是完成本部分功能需要的按钮。图形使用Java的Graphics对象绘制,不得使用第三方类库。 (4) 查询排序功能 <1> 在“查询输入框”输入“学号、姓名或成绩”的全部或部分,成绩列表中只显示包括输入数据的成绩项目。 <2> 点击表格的“列标题”,可以自动按该列排序,2次点击可以切换“升序”和“降序”。 说明:图1黑色注释框指出的是查询界面的位置。提示:JTabel的RowSorter。 提交要求: 1. 打包为可以执行的JAR文档,其中要包含源程序文件。 2.实验报告,简要说明程序的设计思路,不要贴代码,不超过5页(含封面)WORD文档,扩展名为.DOC。 成绩评定说明: 1. 前4个实验随堂练习的平均成绩占实验课最终成绩的70%。 2. 综合性实验满分100分,占实验课最终成绩的70%。 3. 综合性实验评分细则 (1) 完成实验要求的前2项,75分----80分 (2) 完成实验要求的前4项,85分----90分 (3) 完成实验要求全部4项,95分----100分 说明:确定分数段后,根据完成的程序结构、运行效率、界面美观等给出具体分数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值