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

java.io.StreamCorruptedException异常:二进制文件读取流头无效

序列化写入/读取二进制文件时抛出StreamCorruptedException异常

我开发了一款从在线街道地图XML文件读取数据的应用,会把单个XML元素解析为存储数据的HashMap。但在尝试将解析后的数据写入二进制分块文件,再通过getAllTagBoundsFromBinaryFile()方法读取时,抛出了java.io.StreamCorruptedException: invalid stream header: 7372000F异常。

我的Tag抽象类继承自HashMap,每个XML元素都会解析为该类的实例,所以写入二进制文件的对象理论上都实现了Serializable接口:

public abstract class Tag<E extends Enum<E>> extends HashMap<E, Object>

负责创建二进制分块文件并写入TagBound(继承自Tag)对象的代码如下:

public class XMLWriter {
    private String directoryPath = "src/main/resources/chunks/";
    // 用于处理/存储.bin文件路径及其对应TagBound的静态类ChunkFiles
    private static ChunkFiles chunkFiles = new ChunkFiles();
    private static int chunkId = 0;

    public XMLWriter(TagBound bounds) {
        initChunkFiles(bounds);    
    }

    public void initChunkFiles(TagBound bounds) {   
        // 将边界分割为更小的块
        for (TagBound parentChunk : Chunk.getQuadrants(bounds).values()) {
            Chunk childChunk = new Chunk(parentChunk); 
            
            for (int j = 0; j < 4; j++) {
                // 获取块中的四个象限之一
                TagBound child = childChunk.getQuadrant(j);

                // 将TagBound与对应的块文件路径加入HashMap:HashMap<TagBound, String>
                chunkFiles.appendChunkFile(child, directoryPath + "chunk_" + chunkId + ".bin");
                // 创建块文件
                createBinaryChunkFile(directoryPath + "chunk_" + chunkId + ".bin", child);
                chunkId++;
            }
        }
    }

    private static void createBinaryChunkFile(String path, TagBound bound){
      try{
          File file = new File(path);
          if (!file.exists()){
             file.createNewFile();
          }
       ObjectOutputStream oos = new AppendableObjectOutputStream(new FileOutputStream (path, true));
            oos.writeObject(bound);
            oos.flush();
            oos.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        
    }

     private static class AppendableObjectOutputStream extends ObjectOutputStream implements Serializable {
          public AppendableObjectOutputStream(OutputStream out) throws IOException {
            super(out);
          }

          @Override
          protected void writeStreamHeader() throws IOException {}
    }
...

读取二进制文件中TagBound对象的代码:

public static List<TagBound> getAllTagBoundsFromBinaryFile() {
        List<TagBound> tagBounds = new ArrayList<>();
        for (String path : chunkFiles.getChunkFilePaths()) {
            try (FileInputStream fstream = new FileInputStream(path);
                 ObjectInputStream ostream = new ObjectInputStream(fstream)) {
                while (true) {
                    TagBound tagBound = (TagBound) ostream.readObject();
                    tagBounds.add(tagBound);
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        return tagBounds;
    }

问题原因与修复方案

核心问题

写入时用自定义的AppendableObjectOutputStream跳过了序列化流头,但读取时用标准ObjectInputStream会强制检查流头,导致解析失败。同时,追加写入多个对象时,后续对象缺少正确的流上下文,进一步引发异常。

修复步骤

  1. 自定义匹配写入逻辑的输入流
    创建AppendableObjectInputStream类,跳过流头检查,对应写入时的操作:

    private static class AppendableObjectInputStream extends ObjectInputStream {
        public AppendableObjectInputStream(InputStream in) throws IOException {
            super(in);
        }
    
        @Override
        protected void readStreamHeader() throws IOException {
            // 跳过流头验证,匹配写入时的逻辑
        }
    }
    
  2. 修改读取方法
    使用自定义输入流,并通过捕获EOFException终止循环(替代无限循环):

    public static List<TagBound> getAllTagBoundsFromBinaryFile() {
        List<TagBound> tagBounds = new ArrayList<>();
        for (String path : chunkFiles.getChunkFilePaths()) {
            try (FileInputStream fstream = new FileInputStream(path);
                 AppendableObjectInputStream ostream = new AppendableObjectInputStream(fstream)) {
                while (true) {
                    try {
                        TagBound tagBound = (TagBound) ostream.readObject();
                        tagBounds.add(tagBound);
                    } catch (EOFException e) {
                        // 文件读取完毕,退出循环
                        break;
                    }
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        return tagBounds;
    }
    
  3. 额外注意事项

    • 确保TagBound及其内部所有引用的对象都实现Serializable接口,否则会导致序列化失败。
    • 保持写入后正确关闭流的逻辑,避免流状态混乱。

内容的提问来源于stack exchange,提问作者Caniuss

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:53:17