Java读取文件触发java.io.EOFException问题求助
问题描述
我的代码用于创建包含固定长度字符串的文档,但在展示文件内容时抛出java.io.EOFException,错误指向RandomFileHandlerAlex类的decodeFiles方法第104行。我尝试通过校验长度解决但无效,附上完整代码求助。
错误堆栈信息:
java.io.EOFException at java.base/java.io.RandomAccessFile.readFully(RandomAccessFile.java:498) at java.base/java.io.RandomAccessFile.readFully(RandomAccessFile.java:472) at RandomFileHandlerAlex.decodeFiles(RandomFileHandlerAlex.java:104) at RandomFileHandlerAlex.main(RandomFileHandlerAlex.java:20)
原代码:
import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Scanner; public class RandomFileHandlerAlex { public static Scanner input = new Scanner(System.in); public static void main(String[] args) throws IOException { int selection = -1; while (selection != 0) { showMenu(); selection = input.nextInt(); input.nextLine(); // Clear buffer if (selection == 1) { handlePopulations(); } else if (selection == 2) { handleRegion(); } else if (selection == 3) { decodeFiles(); } else if (selection == 4) { modifyFifthPopulationRecord(); } else if (selection == 5) { addPopulationOrRegion(); } } } // Method to display menu options public static void showMenu() { System.out.println("1. Enter populations"); System.out.println("2. Enter region"); System.out.println("3. Decode file"); System.out.println("4. Edit 5th position"); System.out.println("5. Add record"); System.out.println("0. Exit"); } // Method to handle population input and save it to a file public static void handlePopulations() { try (RandomAccessFile file = new RandomAccessFile("population.dat", "rw")) { Scanner scanner = new Scanner(System.in); System.out.println("---------Enter populations--------"); file.seek(file.length()); for (int i = 0; i < 8; i++) { System.out.println("Enter name:"); String name = scanner.nextLine(); name = String.format("%-60s", name); // Set fixed length System.out.println("Enter number of inhabitants:"); int inhabitants = scanner.nextInt(); System.out.println("Enter rt:"); double rt = scanner.nextDouble(); scanner.nextLine(); // Clear buffer System.out.println("Enter postal code:"); String postalCode = scanner.nextLine(); postalCode = String.format("%-5s", postalCode); file.writeUTF(name); // Write name as UTF-8 file.writeInt(inhabitants); // Write inhabitants file.writeDouble(rt); // Write rt file.writeUTF(postalCode); // Write postal code as UTF-8 } } catch (IOException e) { e.printStackTrace(); } } // Method to handle region input and save it to a file public static void handleRegion() { try (RandomAccessFile file = new RandomAccessFile("region.dat", "rw")) { System.out.println("---------Enter regions--------"); file.seek(file.length()); for (int i = 0; i < 8; i++) { System.out.println("Enter name:"); String name = input.nextLine(); name = String.format("%-30s", name); // Set fixed length System.out.println("Enter number of inhabitants:"); int inhabitants = input.nextInt(); System.out.println("Enter rt:"); double rt = input.nextDouble(); input.nextLine(); // Clear buffer file.writeUTF(name); file.writeInt(inhabitants); file.writeDouble(rt); } } catch (IOException e) { e.printStackTrace(); } } // Method to read and display content of population file public static void decodeFiles() { try { File populationFile = new File("population.dat"); if (populationFile.exists() && populationFile.isFile()) { try (RandomAccessFile file = new RandomAccessFile(populationFile, "r")) { while (file.getFilePointer() < file.length()) { byte[] nameBytes = new byte[60]; file.readFully(nameBytes); String name = new String(nameBytes).trim(); int inhabitants = file.readInt(); double rt = file.readDouble(); byte[] postalCodeBytes = new byte[5]; file.readFully(postalCodeBytes); String postalCode = new String(postalCodeBytes).trim(); // Display read data System.out.println("Name: " + name); System.out.println("Inhabitants: " + inhabitants); System.out.println("RT: " + rt); System.out.println("Postal Code: " + postalCode); System.out.println("---------------------------"); } } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("File population.dat does not exist."); } } catch (Exception e) { e.printStackTrace(); } } // Method to modify the fifth population record public static void modifyFifthPopulationRecord() { try { File populationFile = new File("population.dat"); if (populationFile.exists() && populationFile.isFile()) { try (RandomAccessFile file = new RandomAccessFile(populationFile, "rw")) { // Exact size of each record (without UTF headers) long recordSize = 60 + 4 + 8 + 5; long recordCount = file.length() / recordSize; if (recordCount < 5) { System.out.println("File does not contain enough records (at least 5 required)"); return; } file.seek(recordSize * 4); // Position of the fifth record byte[] nameBytes = new byte[60]; file.readFully(nameBytes); String name = new String(nameBytes).trim(); int inhabitants = file.readInt(); double rt = file.readDouble(); byte[] postalCodeBytes = new byte[5]; file.readFully(postalCodeBytes); String postalCode = new String(postalCodeBytes).trim(); // Modify values inhabitants += 100; rt -= 0.05; // Overwrite fifth record with modified values file.seek(recordSize * 4); file.writeBytes(String.format("%-60s", name)); file.writeInt(inhabitants); file.writeDouble(rt); file.writeBytes(String.format("%-5s", postalCode)); System.out.println("Fifth record updated"); } catch (IOException e) { e.printStackTrace(); } } } catch (Exception e) { throw new RuntimeException(e); } } // Method to add a new population or region record public static void addPopulationOrRegion() { System.out.println("1.population 2.region"); int option = input.nextInt(); if (option == 1) { try (RandomAccessFile file = new RandomAccessFile("population.dat", "rw")) { Scanner scanner = new Scanner(System.in); System.out.println("---------Enter a population--------"); file.seek(file.length()); System.out.println("Enter name:"); String name = scanner.nextLine(); name = String.format("%-60s", name); System.out.println("Enter number of inhabitants:"); int inhabitants = scanner.nextInt(); System.out.println("Enter rt:"); double rt = scanner.nextDouble(); scanner.nextLine(); System.out.println("Enter postal code:"); String postalCode = scanner.nextLine(); postalCode = String.format("%-5s", postalCode); file.writeUTF(name); file.writeInt(inhabitants); file.writeDouble(rt); file.writeUTF(postalCode); } catch (IOException e) { e.printStackTrace(); } } else if (option == 2) { try (RandomAccessFile file = new RandomAccessFile("region.dat", "rw")) { System.out.println("---------Enter a region--------"); file.seek(file.length()); System.out.println("Enter name:"); String name = input.nextLine(); name = String.format("%-30s", name); System.out.println("Enter number of inhabitants:"); int inhabitants = input.nextInt(); System.out.println("Enter rt:"); double rt = input.nextDouble(); input.nextLine(); file.writeUTF(name); file.writeInt(inhabitants); file.writeDouble(rt); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("Invalid option"); } } }
问题原因与修复方案
核心问题
写入和读取方式完全不匹配:
- 写入时用
writeUTF(),该方法会在字符串字节前额外写入2个字节的长度前缀,导致实际写入的字节数比你设定的固定长度多2字节。 - 读取时直接用
readFully()读取固定字节数,完全忽略了前缀字节,后续所有读取位置全部偏移,最终触发EOF异常。 - 此外,修改记录时用
writeBytes()写入,和初始的writeUTF()不兼容,进一步破坏文件结构。
修复后完整代码
import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Scanner; public class RandomFileHandlerAlex { public static Scanner input = new Scanner(System.in); public static void main(String[] args) throws IOException { int selection = -1; while (selection != 0) { showMenu(); selection = input.nextInt(); input.nextLine(); // 清空缓冲区 if (selection == 1) { handlePopulations(); } else if (selection == 2) { handleRegion(); } else if (selection == 3) { decodeFiles(); } else if (selection == 4) { modifyFifthPopulationRecord(); } else if (selection == 5) { addPopulationOrRegion(); } } } // 显示菜单选项 public static void showMenu() { System.out.println("1. 输入人口数据"); System.out.println("2. 输入区域数据"); System.out.println("3. 解码文件"); System.out.println("4. 编辑第5条记录"); System.out.println("5. 添加记录"); System.out.println("0. 退出"); } // 处理人口输入并保存到文件 public static void handlePopulations() { try (RandomAccessFile file = new RandomAccessFile("population.dat", "rw")) { Scanner scanner = new Scanner(System.in); System.out.println("---------输入人口数据--------"); file.seek(file.length()); for (int i = 0; i < 8; i++) { System.out.println("输入名称:"); String name = scanner.nextLine(); name = String.format("%-60s", name); // 固定长度60 System.out.println("输入居民数量:"); int inhabitants = scanner.nextInt(); System.out.println("输入rt值:"); double rt = scanner.nextDouble(); scanner.nextLine(); // 清空缓冲区 System.out.println("输入邮政编码:"); String postalCode = scanner.nextLine(); postalCode = String.format("%-5s", postalCode); // 固定长度5 // 用writeBytes写入固定长度字符串,无前缀 file.writeBytes(name); file.writeInt(inhabitants); file.writeDouble(rt); file.writeBytes(postalCode); } } catch (IOException e) { e.printStackTrace(); } } // 处理区域输入并保存到文件 public static void handleRegion() { try (RandomAccessFile file = new RandomAccessFile("region.dat", "rw")) { System.out.println("---------输入区域数据--------"); file.seek(file.length()); for (int i = 0; i < 8; i++) { System.out.println("输入名称:"); String name = input.nextLine(); name = String.format("%-30s", name); // 固定长度30 System.out.println("输入居民数量:"); int inhabitants = input.nextInt(); System.out.println("输入rt值:"); double rt = input.nextDouble(); input.nextLine(); // 清空缓冲区 file.writeBytes(name); file.writeInt(inhabitants); file.writeDouble(rt); } } catch (IOException e) { e.printStackTrace(); } } // 读取并展示人口文件内容 public static void decodeFiles() { try { File populationFile = new File("population.dat"); if (populationFile.exists() && populationFile.isFile()) { try (RandomAccessFile file = new RandomAccessFile(populationFile, "r")) { // 每条记录的固定长度:60(name) +4(int)+8(double)+5(postal)=77字节 long recordSize = 60 + 4 + 8 + 5; long totalRecords = file.length() / recordSize; for (int i = 0; i < totalRecords; i++) { byte[] nameBytes = new byte[60]; file.readFully(nameBytes); String name = new String(nameBytes).trim(); int inhabitants = file.readInt(); double rt = file.readDouble(); byte[] postalCodeBytes = new byte[5]; file.readFully(postalCodeBytes); String postalCode = new String(postalCodeBytes).trim(); // 展示读取的数据 System.out.println("名称: " + name); System.out.println("居民数量: " + inhabitants); System.out.println("RT值: " + rt); System.out.println("邮政编码: " + postalCode); System.out.println("---------------------------"); } } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("文件population.dat不存在。"); } } catch (Exception e) { e.printStackTrace(); } } // 修改第5条人口记录 public static void modifyFifthPopulationRecord() { try { File populationFile = new File("population.dat"); if (populationFile.exists() && populationFile.isFile()) { try (RandomAccessFile file = new RandomAccessFile(populationFile, "rw")) { // 每条记录的固定长度:60+4+8+5=77字节 long recordSize = 60 + 4 + 8 + 5; long recordCount = file.length() / recordSize; if (recordCount < 5) { System.out.println("文件记录不足5条,无法修改"); return; } // 定位到第5条记录(索引从0开始,所以是4*recordSize) file.seek(recordSize * 4); byte[] nameBytes = new byte[60]; file.readFully(nameBytes); String name = new String(nameBytes).trim(); int inhabitants = file.readInt(); double rt = file.readDouble(); byte[] postalCodeBytes = new byte[5]; file.readFully(postalCodeBytes); String postalCode = new String(postalCodeBytes).trim(); // 修改值 inhabitants += 100; rt -= 0.05; // 覆盖第5条记录 file.seek(recordSize * 4); file.writeBytes(String.format("%-60s", name)); file.writeInt(inhabitants); file.writeDouble(rt); file.writeBytes(String.format("%-5s", postalCode)); System.out.println("第5条记录已更新"); } catch (IOException e) { e.printStackTrace(); } } } catch (Exception e) { throw new RuntimeException(e); } } // 添加新的人口或区域记录 public static void addPopulationOrRegion() { System.out.println("1.人口数据 2.区域数据"); int option = input.nextInt(); input.nextLine(); // 清空缓冲区 if (option == 1) { try (RandomAccessFile file = new RandomAccessFile("population.dat", "rw")) { Scanner scanner = new Scanner(System.in); System.out.println("---------输入人口数据--------"); file.seek(file.length()); System.out.println("输入名称:"); String name = scanner.nextLine(); name = String.format("%-60s", name); System.out.println("输入居民数量:"); int inhabitants = scanner.nextInt(); System.out.println("输入rt值:"); double rt = scanner.nextDouble(); scanner.nextLine(); System.out.println("输入邮政编码:"); String postalCode = scanner.nextLine(); postalCode = String.format("%-5s", postalCode);
相关产品推荐
相关产品推荐

