今天刚好没事,看了下CSDN,看到有这个题,一时兴起就做了一下
原文链接:https://blog.csdn.net/weixin_45791445/article/details/108890171
作者是:小康小白
开始看的时候感觉很简单,半天就可以写完了,写着写着突然想尝试一下NIO来代替普通IO流,不太熟悉缓冲区结构,查了点资料,加调错,结果就花了一天时间。。
当然,我知道NIO只是在读大文件时候会用到,在读小文件的时候,效率还比不上普通IO流,不过既然是练习,尝试一下新的API也是一种提升
如果是正式项目,我会把所有的静态变量提取到配置文件中,或者单独写在一个constant类中统一保存,而不是直接写在业务类中
下面贴一下代码,写完我也没细看了,有可以优化的地方希望大佬提出来,小弟学习一下
由于在控制台完成,也不涉及数据库,所以总共是2个类,一个是实体类,一个是业务类。业务类由于太长,建议拷贝到IDE工具中再看方便一些
实体类:
import java.util.List;
public class ExamResultBO {
/**
* 学生编号
*/
private String id;
/**
* 试题
*/
private List<String> examQuestions;
/**
* 学生的选项
*/
private List<String> choice;
/**
* 试题的正确答案
*/
private List<String> correctAnswer;
/**
* 每一题的得分,由于这里不需要每一题的分数,所以就只记录总分
*/
private int score;
/**
* 完成答题所花费的时间
*/
private long spendTime;
//下面是get和set方法,就不贴了
}
业务类:
import com.dahua.practise.pojo.ExamResultBO;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class StudentMath {
/**
* 1.1【问题描述】
* 编写一个帮助小学生练习数学的程序,帮助小学生练习100以内的四种数学运算:加、减、乘、除。
* 1.2【基本要求】
* a) 程序应先询问用户的ID号(ID号包括两个大写字母和4位数字),例如:
* 请输入用户ID号:AB1234 程序应对输入的ID号验证,符合ID号要求的格式,然后程序提示三种选择: (1)开始测试 (2)检查分数 (3)退出
* b) 测试:该程序将给出10道数学题,例如:
* 12 * 3 =36
* 48 + 32 =80
* 56 / 28 =2
* 注意:
* i)学生将依次回答每一个问题(在等于号后面给出答案),然后给出下一道题。
* ii)试题应包含四种数学运算:加、减、乘、除,它们是随机产生的。相邻的问题应该是不同的操作,每个操作必须至少出现一次。
* iii)为每道题随机生成数字,但必须确保参与运算的数字和结果都小于100且大于零的整数。
* iv)十道题做完后,记录学生完成这十道题所用的时间。
* v)给每个学生一个分数。将该学生的ID、成绩和使用时间保存到一个名为record.txt的文件中。
* vi)在屏幕上输出以下信息:
* 问题 | 正确答案 | 你的答案
* c) 成绩检查:从文件“record.txt”中列出该学生的所有历史成绩。例如:
* 你以前的记录是:
* AB1234 80 150秒
* AB1234 50 182秒
* AB1234 90 98秒
*/
//生成题目的数量
private static final int QUESTION_NUM = 5;
private static final int TOTAL_SCORE = 100;
private static final String FILE_PATH = "D:/result.txt";
public static void main(String[] args) {
//检测用户名
String user = checkUserId();
//给提示做出选择,(1)开始测试 (2)检查分数 (3)退出
boolean repeatFlag = true;
while (repeatFlag) {
System.out.println("请做出选择:(1)开始测试 (2)检查分数 (3)退出");
String choice = new Scanner(System.in).nextLine();
switch (choice) {
case "1":
exam(user);
repeatFlag = false;
break;
case "2":
checkScore(user);
repeatFlag = false;
break;
case "3":
repeatFlag = false;
break;
default:
System.out.println("您的输入有误,请重新输入");
break;
}
}
}
private static void exam(String user) {
//生成计算过程,更新考试结果resultMap,并且需要拿到一个用于屏幕显示的Map
ExamResultBO examResult = manageExam();
examResult.setId(user);
//展示结果
System.out.println("问题\t正确答案\t你的答案");
for (int i = 0; i < QUESTION_NUM; i++) {
System.out.println(examResult.getExamQuestions().get(i) + "\t" +
examResult.getCorrectAnswer().get(i) + "\t" +
examResult.getChoice().get(i));
}
//序列化结果到磁盘
NIOWrite(examResult);
}
/**
* 序列化结果到磁盘
*
* @param examResult 考试结果
*/
private static void NIOWrite(ExamResultBO examResult) {
FileOutputStream fos = null;
try {
File file = new File(FILE_PATH);
fos = new FileOutputStream(file, true);
FileChannel channel = fos.getChannel();
ByteBuffer bufferHead = StandardCharsets.UTF_8.encode("小学生一百以内加减法测试题\n");
String body = examResult.getId() + "\t" + examResult.getScore() + "\t" +
examResult.getSpendTime() + "\n";
ByteBuffer bufferBody = StandardCharsets.UTF_8.encode(body);
if (file.length() == 0) {
channel.write(bufferHead);
}
channel.write(bufferBody);
channel.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 生成计算的过程
*/
private static ExamResultBO manageExam() {
Random random = new Random();
Scanner scanner = new Scanner(System.in);
//需要返回用于展示的map
ExamResultBO result = new ExamResultBO();
List<String> examQuestions = new ArrayList<>();
List<String> studentAnswer = new ArrayList<>();
List<String> correctAnswer = new ArrayList<>();
int scorePerQuestion = TOTAL_SCORE / QUESTION_NUM;
int getScore = 0;
//参与计算的两个数字
int a = 0;
int b = 0;
//要求加减乘除都必须出先至少1次
List<Integer> optList = getOptList();
long startTime = System.currentTimeMillis();
//开始测验
for (int i = 0; i < QUESTION_NUM; i++) {
int finalI = i;
int opt = Optional.ofNullable(optList).map(list -> list.get(finalI)).orElse(-1);
String question = "";
String answer = "";
switch (opt) {
case 0:
//不计算超过100的加法
do {
a = random.nextInt(99) + 1;
b = random.nextInt(99) + 1;
} while (a + b > 100);
question = a + " + " + b + " = ";
System.out.print(question);
answer = scanner.nextLine();
//写入到结果集中,其中userId拿到外部补充
examQuestions.add(question);
studentAnswer.add(answer);
correctAnswer.add("" + (a + b));
getScore += ("" + (a + b)).equals(answer) ? scorePerQuestion : 0;
break;
case 1:
//不计算负数
do {
a = random.nextInt(99) + 1;
b = random.nextInt(99) + 1;
} while (a - b < 0);
question = a + " - " + b + " = ";
System.out.print(question);
answer = scanner.nextLine();
examQuestions.add(question);
studentAnswer.add(answer);
correctAnswer.add("" + (a - b));
getScore += ("" + (a - b)).equals(answer) ? scorePerQuestion : 0;
break;
case 2:
//不计算超过100的乘法
do {
a = random.nextInt(99) + 1;
b = random.nextInt(99) + 1;
} while (a * b > 100);
question = a + " * " + b + " = ";
System.out.print(question);
answer = scanner.nextLine();
examQuestions.add(question);
studentAnswer.add(answer);
correctAnswer.add("" + (a * b));
getScore += ("" + (a * b)).equals(answer) ? scorePerQuestion : 0;
break;
case 3:
//只生成可以整除的a和b
do {
a = random.nextInt(99) + 1;
b = random.nextInt(99) + 1;
} while (a % b != 0);
question = a + " / " + b + " = ";
System.out.print(question);
answer = scanner.nextLine();
examQuestions.add(question);
studentAnswer.add(answer);
correctAnswer.add("" + (a / b));
getScore += ("" + (a / b)).equals(answer) ? scorePerQuestion : 0;
break;
default:
break;
}
}
result.setSpendTime(System.currentTimeMillis() - startTime);
result.setExamQuestions(examQuestions);
result.setChoice(studentAnswer);
result.setCorrectAnswer(correctAnswer);
result.setScore(getScore);
return result;
}
private static List<Integer> getOptList() {
if (QUESTION_NUM < 4) {
throw new IllegalArgumentException("题目数量少于4,无法生成");
}
List<Integer> resultList = new ArrayList<>(QUESTION_NUM);
List<Integer> staticList = Arrays.asList(0, 1, 2, 3);
List<Integer> randomList = new ArrayList<>(QUESTION_NUM - 4);
Random random = new Random();
for (int i = 0; i < QUESTION_NUM - 4; i++) {
int a = random.nextInt(4);
randomList.add(a);
}
resultList.addAll(staticList);
resultList.addAll(randomList);
if (CollectionUtils.isEmpty(resultList)) {
return null;
}
//重新打乱排序
Collections.shuffle(resultList);
return resultList;
}
private static void checkScore(String user) {
//这里得到的结果集已经完成用户名匹配
List<ExamResultBO> resultList = readFile(user);
if (CollectionUtils.isEmpty(resultList)){
System.out.println("系统中没有你的考试记录,请先进行一次考试");
return;
}
System.out.println("你以前的记录是:");
for (ExamResultBO result : resultList) {
System.out.println(result.getId() + " " + result.getScore() + " " + result.getSpendTime() / 1000 + "秒");
}
}
private static List<ExamResultBO> readFile(String user) {
File file = new File(FILE_PATH);
String str = null;
FileInputStream fis = null;
List<ExamResultBO> examResultList = new ArrayList<>();
try {
fis = new FileInputStream(file);
FileChannel channel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
byte[] bytes = new byte[0];
while (channel.read(buffer) != -1) {
//读取到缓冲区数组
byte[] readBytes = buffer.array();
//保存循环开始时上一个byte[]的长度
int oldLength = bytes.length;
//把byte[]长度扩充到缓冲区position指针的长度
bytes = Arrays.copyOf(bytes, bytes.length + buffer.position());
//把读取的数据放入bytes[],注意界限是position指针位置,防止最后一行出现其他数据
System.arraycopy(readBytes, 0, bytes, oldLength, buffer.position());
//初始化buffer指针
buffer.clear();
}
str = new String(bytes);
//对str进行封装
String[] arr = str.split("\n");
for (String s : arr) {
if (!s.contains("\t")) {
//如果是第一行,则不包含制表符
continue;
}
ExamResultBO examResult = new ExamResultBO();
String[] val = s.split("\t");
if (user.equals(val[0])) {
//结果集中只写入匹配用户名的记录
examResult.setId(val[0]);
examResult.setScore(Integer.parseInt(val[1]));
examResult.setSpendTime(Long.parseLong(val[2]));
examResultList.add(examResult);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return examResultList;
}
/**
* 检测用户名
*/
private static String checkUserId() {
String user = null;
while (true) {
System.out.print("请输入两个大写字母和4位数字的ID:");
user = new Scanner(System.in).nextLine();
if (user.matches("^[A-Z]{2}[0-9]{4}$")) {
break;
}
System.out.println("用户ID输入有误,请重新输入");
}
return user;
}
}
版权声明:本文为u014086799原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。