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

ArrayList序列化:如何向已存在的序列化文件追加新ArrayList?

关于Java序列化追加写入ArrayList的问题解答

嘿,这个序列化追加的坑我之前也踩过!先直接给你结论:直接用ObjectOutputStream加FileOutputStream(true)追加写入是行不通的,原因和解决方法我给你拆解清楚:

为什么直接追加会失败?

ObjectOutputStream在初始化的时候,会自动写入一个序列化流头部(Stream Header)。第一次写入文件时,这个头部是正常的,能被ObjectInputStream识别;但当你第二次追加写入时,新的ObjectOutputStream又会写入一个新的头部,而ObjectInputStream读取时,只会解析第一个头部,后续的头部会被当成无效数据,导致读取失败或者抛出异常。

两种可行的解决方案

方案一:合并现有列表后重写文件(你提到的可行方案)

这是最稳妥、最不容易出错的方式:每次添加新客户时,先把文件里已有的ArrayList<Customer>反序列化读出来,把新客户加入到这个列表里,再重新序列化覆盖整个文件。

示例代码:

// 先实现反序列化方法
public ArrayList<Customer> deserializeBank() {
    File file = new File("data.ser");
    if (!file.exists()) {
        return new ArrayList<>();
    }
    try (ObjectInputStream is = new ObjectInputStream(new FileInputStream(file))) {
        return (ArrayList<Customer>) is.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
        return new ArrayList<>();
    }
}

// 然后修改序列化方法
public void serializeBank(ArrayList<Customer> newCustomers) {
    ArrayList<Customer> existingCustomers = deserializeBank();
    existingCustomers.addAll(newCustomers);
    try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("data.ser"))) {
        os.writeObject(existingCustomers);
    } catch (IOException i) {
        i.printStackTrace();
    }
}

方案二:自定义OutputStream跳过重复头部,实现真正的追加

如果你坚持要直接追加而不重写整个文件,可以自定义一个ObjectOutputStream的子类,覆盖writeStreamHeader()方法,当文件已经存在(即追加模式)时,跳过头部的写入。

示例代码:

// 自定义可追加的ObjectOutputStream
class AppendableObjectOutputStream extends ObjectOutputStream {
    public AppendableObjectOutputStream(OutputStream out) throws IOException {
        super(out);
    }

    @Override
    protected void writeStreamHeader() throws IOException {
        // 追加模式下,不写入新的流头部
        reset();
    }
}

// 修改后的序列化方法
public void serializeBank(ArrayList<Customer> newCustomers) {
    File file = new File("data.ser");
    boolean isAppend = file.exists() && file.length() > 0;
    try (OutputStream fos = new FileOutputStream(file, true);
         ObjectOutputStream os = isAppend ? new AppendableObjectOutputStream(fos) : new ObjectOutputStream(fos)) {
        os.writeObject(newCustomers);
    } catch (IOException i) {
        i.printStackTrace();
    }
}

注意:读取的时候要循环读取,直到文件结束:

public ArrayList<Customer> deserializeBank() {
    ArrayList<Customer> allCustomers = new ArrayList<>();
    File file = new File("data.ser");
    if (!file.exists()) {
        return allCustomers;
    }
    try (ObjectInputStream is = new ObjectInputStream(new FileInputStream(file))) {
        while (true) {
            try {
                ArrayList<Customer> customers = (ArrayList<Customer>) is.readObject();
                allCustomers.addAll(customers);
            } catch (EOFException e) {
                // 读取到文件末尾,结束循环
                break;
            }
        }
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
    return allCustomers;
}

额外提醒

  • 确保Customer类的serialVersionUID保持不变,否则反序列化时会抛出InvalidClassException。
  • 追加写入的方式虽然节省了重写文件的时间,但如果文件损坏,可能会导致部分数据无法恢复;而重写整个文件的方式数据完整性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:26:41