You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PAIR/src/main/java/com/service/FileIOService.java

242 lines
8.1 KiB

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<String, List<User>> 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<Map<String, List<User>>>(){}.getType();
Map<String, List<User>> data = FileUtils.readJsonToObject(USERS_FILE, type);
List<User> 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<User> loadAllUsers() throws IOException {
if (!FileUtils.exists(USERS_FILE)) {
return new ArrayList<>();
}
Type type = new TypeToken<Map<String, List<User>>>(){}.getType();
Map<String, List<User>> data = FileUtils.readJsonToObject(USERS_FILE, type);
return data.get("users");
}
public User findUserByUsername(String username) throws IOException {
List<User> 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<ChoiceQuestion> questions = history.getQuestions();
List<Integer> 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<String> getHistoryQuestions() throws IOException {
List<String> 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<ChoiceQuestion> questions = history.getQuestions();
List<Integer> 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("[\\\\/:*?\"<>|]", "_");
}
}