|
|
|
|
@ -8,6 +8,7 @@ import java.nio.file.Paths;
|
|
|
|
|
import java.nio.file.StandardOpenOption;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
@ -17,28 +18,20 @@ import java.util.stream.Collectors;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 负责文件读写,现已支持将试卷保存为格式化的 .txt 文件。
|
|
|
|
|
* 负责文件读写,现已修复Stream关闭异常。
|
|
|
|
|
*/
|
|
|
|
|
public class FileManager {
|
|
|
|
|
private static final Path BASE_PATH = Paths.get("generated_papers");
|
|
|
|
|
// 格式化器,用于生成 "年-月-日-时-分-秒" 格式的文件名
|
|
|
|
|
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将生成的选择题试卷以 .txt 格式保存到文件。
|
|
|
|
|
* @param username 用户名
|
|
|
|
|
* @param paperContent 包含ChoiceQuestion对象的试卷列表
|
|
|
|
|
* @return 保存成功后的文件路径
|
|
|
|
|
*/
|
|
|
|
|
public String savePaper(String username, List<ChoiceQuestion> paperContent) throws IOException {
|
|
|
|
|
Path userDir = BASE_PATH.resolve(username);
|
|
|
|
|
Files.createDirectories(userDir);
|
|
|
|
|
|
|
|
|
|
String timestamp = LocalDateTime.now().format(FORMATTER);
|
|
|
|
|
String fileName = timestamp + ".txt"; // 文件后缀改为 .txt
|
|
|
|
|
String fileName = timestamp + ".txt";
|
|
|
|
|
Path filePath = userDir.resolve(fileName);
|
|
|
|
|
|
|
|
|
|
// --- 核心修改:构建 .txt 文件内容 ---
|
|
|
|
|
StringBuilder formattedContent = new StringBuilder();
|
|
|
|
|
formattedContent.append("数学试卷\n");
|
|
|
|
|
formattedContent.append("用户: ").append(username).append("\n");
|
|
|
|
|
@ -47,16 +40,13 @@ public class FileManager {
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < paperContent.size(); i++) {
|
|
|
|
|
ChoiceQuestion question = paperContent.get(i);
|
|
|
|
|
// 写入题号和题干
|
|
|
|
|
formattedContent.append(i + 1).append(". ").append(question.questionText()).append("\n");
|
|
|
|
|
|
|
|
|
|
// 写入四个选项
|
|
|
|
|
char optionChar = 'A';
|
|
|
|
|
for (String option : question.options()) {
|
|
|
|
|
formattedContent.append(" ").append(optionChar++).append(". ").append(option).append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (可选) 写入正确答案,方便核对
|
|
|
|
|
String correctAnswer = question.options().get(question.correctOptionIndex());
|
|
|
|
|
formattedContent.append(" [正确答案: ").append(correctAnswer).append("]\n\n");
|
|
|
|
|
}
|
|
|
|
|
@ -65,11 +55,6 @@ public class FileManager {
|
|
|
|
|
return filePath.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* (已修改) 加载指定用户的所有历史题目的题干文本,用于查重。
|
|
|
|
|
* @param username 用户名
|
|
|
|
|
* @return 包含所有历史题干文本的Set集合
|
|
|
|
|
*/
|
|
|
|
|
public Set<String> loadExistingQuestions(String username) {
|
|
|
|
|
Path userDir = BASE_PATH.resolve(username);
|
|
|
|
|
if (!Files.exists(userDir)) {
|
|
|
|
|
@ -78,8 +63,10 @@ public class FileManager {
|
|
|
|
|
|
|
|
|
|
try (Stream<Path> stream = Files.walk(userDir)) {
|
|
|
|
|
return stream
|
|
|
|
|
.filter(file -> !Files.isDirectory(file) && file.toString().endsWith(".txt")) // 只读取 .txt 文件
|
|
|
|
|
.flatMap(this::readQuestionTextsFromTxtFile) // 使用新的解析方法
|
|
|
|
|
.filter(file -> !Files.isDirectory(file) && file.toString().endsWith(".txt"))
|
|
|
|
|
// --- 核心修改在这里 (Part 1) ---
|
|
|
|
|
// flatMap现在操作的是一个由List生成的、全新的、开放的流
|
|
|
|
|
.flatMap(file -> readQuestionTextsFromTxtFile(file).stream())
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.err.println("错误:读取历史文件失败 - " + e.getMessage());
|
|
|
|
|
@ -88,22 +75,24 @@ public class FileManager {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* (新增) 从单个 .txt 文件中解析出所有题目的题干。
|
|
|
|
|
* (已修改) 从单个 .txt 文件中解析出所有题目的题干。
|
|
|
|
|
* @param file 要读取的单个试卷文件的路径对象 (Path)。
|
|
|
|
|
* @return 一个包含该文件中所有题干字符串的流 (Stream)。
|
|
|
|
|
* @return 一个包含该文件中所有题干字符串的列表 (List)。
|
|
|
|
|
*/
|
|
|
|
|
private Stream<String> readQuestionTextsFromTxtFile(Path file) {
|
|
|
|
|
private List<String> readQuestionTextsFromTxtFile(Path file) {
|
|
|
|
|
// --- 核心修改在这里 (Part 2) ---
|
|
|
|
|
// try-with-resources现在可以安全地关闭流,因为它在方法返回前已经被 .collect() 完全消耗了
|
|
|
|
|
try (Stream<String> lines = Files.lines(file)) {
|
|
|
|
|
// 正则表达式,用于匹配 "1. 3 + 5" 这样的行并提取出 "3 + 5"
|
|
|
|
|
Pattern questionPattern = Pattern.compile("^\\d+\\.\\s+(.*)");
|
|
|
|
|
return lines
|
|
|
|
|
.map(String::trim)
|
|
|
|
|
.map(questionPattern::matcher)
|
|
|
|
|
.filter(Matcher::matches)
|
|
|
|
|
.map(matcher -> matcher.group(1).trim());
|
|
|
|
|
.map(matcher -> matcher.group(1).trim())
|
|
|
|
|
.collect(Collectors.toList()); // 将流的结果收集到一个List中
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.err.println("错误:读取文件 " + file + " 失败 - " + e.getMessage());
|
|
|
|
|
return Stream.empty();
|
|
|
|
|
return Collections.emptyList(); // 发生错误时返回一个空列表
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|