package com.service; import com.model.*; import com.util.FileUtils; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.IOException; import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.util.*; /** * 文件IO服务 * 负责所有数据的读写操作 */ public class FileIOService { private static final String DATA_DIR = "data"; private static final String USERS_DIR = DATA_DIR + "/users"; private static final String HISTORY_DIR = DATA_DIR + "/history"; private static final String USERS_FILE = DATA_DIR + "/users.json"; private static final String CURRENT_USER_FILE = DATA_DIR + "/current_user.json"; private static final Gson gson = new GsonBuilder() .setPrettyPrinting() .setDateFormat("yyyy-MM-dd HH:mm:ss") .create(); // ==================== 初始化 ==================== public void initDataDirectory() throws IOException { FileUtils.createDirectoryIfNotExists(DATA_DIR); FileUtils.createDirectoryIfNotExists(USERS_DIR); FileUtils.createDirectoryIfNotExists(HISTORY_DIR); if (!FileUtils.exists(USERS_FILE)) { Map> data = new HashMap<>(); data.put("users", new ArrayList<>()); FileUtils.saveAsJson(data, USERS_FILE); } System.out.println("✓ 数据目录初始化完成"); } // ==================== 用户操作 ==================== public void saveUser(User user) throws IOException { Type type = new TypeToken>>(){}.getType(); Map> data = FileUtils.readJsonToObject(USERS_FILE, type); List users = data.get("users"); boolean found = false; for (int i = 0; i < users.size(); i++) { if (users.get(i).getUsername().equals(user.getUsername())) { users.set(i, user); found = true; break; } } if (!found) { users.add(user); } FileUtils.saveAsJson(data, USERS_FILE); } public List loadAllUsers() throws IOException { if (!FileUtils.exists(USERS_FILE)) { return new ArrayList<>(); } Type type = new TypeToken>>(){}.getType(); Map> data = FileUtils.readJsonToObject(USERS_FILE, type); return data.get("users"); } public User findUserByUsername(String username) throws IOException { List users = loadAllUsers(); for (User user : users) { if (user.getUsername().equals(username)) { return user; } } return null; } public boolean isUsernameExists(String username) throws IOException { return findUserByUsername(username) != null; } public void saveCurrentUser(User user) throws IOException { FileUtils.saveAsJson(user, CURRENT_USER_FILE); } public User loadCurrentUser() throws IOException { if (!FileUtils.exists(CURRENT_USER_FILE)) { return null; } return FileUtils.readJsonToObject(CURRENT_USER_FILE, User.class); } public void clearCurrentUser() { FileUtils.deleteFile(CURRENT_USER_FILE); } // ==================== 答题历史操作 ==================== public void saveQuizHistory(QuizHistory history) throws IOException { String filename = HISTORY_DIR + "/" + sanitizeFilename(history.getUsername()) + "_" + System.currentTimeMillis() + ".txt"; StringBuilder content = new StringBuilder(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); content.append("========== 答题记录 ==========\n"); content.append("用户:").append(history.getUsername()).append("\n"); content.append("时间:").append(dateFormat.format(history.getTimestamp())).append("\n"); content.append("总分:").append(history.getScore()).append(" 分\n"); // 调用 QuizService 的业务方法计算正确数和错误数 int correctCount = calculateCorrectCount(history); int wrongCount = history.getQuestions().size() - correctCount; content.append("正确:").append(correctCount).append(" 题 "); content.append("错误:").append(wrongCount).append(" 题\n"); content.append("=============================\n\n"); List questions = history.getQuestions(); List userAnswers = history.getUserAnswers(); for (int i = 0; i < questions.size(); i++) { ChoiceQuestion q = questions.get(i); Integer userAnswer = userAnswers.get(i); content.append("【题目 ").append(i + 1).append("】\n"); content.append(q.getQuestionText()).append("\n"); List options = q.getOptions(); for (int j = 0; j < options.size(); j++) { content.append((char)('A' + j)).append(". ") .append(options.get(j)).append(" "); } content.append("\n"); int correctIndex = getCorrectAnswerIndex(q); content.append("正确答案:").append((char)('A' + correctIndex)).append("\n"); content.append("用户答案:"); if (userAnswer != null) { content.append((char)('A' + userAnswer)); } else { content.append("未作答"); } content.append("\n"); boolean isCorrect = (userAnswer != null && userAnswer == correctIndex); content.append("结果:").append(isCorrect ? "✓ 正确" : "✗ 错误").append("\n\n"); } FileUtils.writeStringToFile(filename, content.toString()); } public List getHistoryQuestions() throws IOException { List historyQuestions = new ArrayList<>(); File[] files = FileUtils.listFiles(HISTORY_DIR); Arrays.sort(files, (f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified())); int count = 0; for (File file : files) { if (count++ >= 20) break; try { String content = FileUtils.readFileToString(file.getAbsolutePath()); String[] lines = content.split("\n"); for (int i = 0; i < lines.length; i++) { if (lines[i].startsWith("【题目")) { if (i + 1 < lines.length) { String questionText = lines[i + 1].trim(); if (!questionText.isEmpty()) { historyQuestions.add(questionText); } } } } } catch (IOException e) { System.err.println("读取历史文件失败: " + file.getName()); } } return historyQuestions; } // ==================== 业务逻辑方法(从 Model 移过来)==================== /** * 计算答题历史的正确数 */ private int calculateCorrectCount(QuizHistory history) { int count = 0; List questions = history.getQuestions(); List userAnswers = history.getUserAnswers(); for (int i = 0; i < questions.size(); i++) { ChoiceQuestion question = questions.get(i); Integer userAnswer = userAnswers.get(i); if (userAnswer != null && userAnswer == getCorrectAnswerIndex(question)) { count++; } } return count; } /** * 获取题目的正确答案索引 */ private int getCorrectAnswerIndex(ChoiceQuestion question) { return question.getOptions().indexOf(question.getCorrectAnswer()); } // ==================== 工具方法 ==================== private String sanitizeFilename(String filename) { if (filename == null) { return "unknown"; } return filename.replaceAll("[\\\\/:*?\"<>|]", "_"); } }