You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:09:49