You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java读取二进制文件并添加至ArrayList的技术求助

解决Java中二进制文件与ArrayList的读写问题

Hey there! I see you've got the hang of working with ArrayLists and text files in Java, but binary files are throwing you for a loop. Let's break this down into actionable steps and alternatives to your initial comma-based idea.

一、基础导入类

处理二进制文件读写,你需要导入这些核心类(大多来自java.io包):

  • java.io.FileInputStream:从二进制文件读取字节流
  • java.io.FileOutputStream:向二进制文件写入字节流
  • java.io.ObjectInputStream:读取序列化的Java对象
  • java.io.ObjectOutputStream:写入序列化的Java对象
  • java.io.IOException:处理IO操作的异常
  • java.util.ArrayList:你的核心集合类
  • (可选)java.nio.charset.StandardCharsets:用于统一字符串编码

二、推荐方案:对象序列化(最简单直接)

因为StringArrayList都实现了Serializable接口,你可以直接把整个ArrayList序列化到二进制文件,不用手动处理分隔符。这完全避开了你遇到的split困境,是最省心的方案。

写入二进制文件示例

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.io.IOException;

public class BinaryWriter {
    public static void main(String[] args) {
        ArrayList<String> dataList = new ArrayList<>();
        // 添加你的8个String元素
        dataList.add("user_id");
        dataList.add("username");
        dataList.add("email");
        dataList.add("phone");
        dataList.add("address");
        dataList.add("age");
        dataList.add("gender");
        dataList.add("status");

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user_data.bin"))) {
            oos.writeObject(dataList); // 直接写入整个ArrayList
            System.out.println("数据已成功写入二进制文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

读取二进制文件到ArrayList示例

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.io.IOException;
import java.io.ClassNotFoundException;

public class BinaryReader {
    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user_data.bin"))) {
            // 读取并强制转换为ArrayList<String>
            ArrayList<String> loadedList = (ArrayList<String>) ois.readObject();
            
            // 验证读取结果
            for (String field : loadedList) {
                System.out.println(field);
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

三、替代方案:自定义二进制格式(手动控制字节)

如果你不想用序列化(比如需要和其他语言交互二进制文件),可以自定义格式:先写入每个字符串的长度(用固定4字节的int),再写入字符串的UTF-8字节。这样读取时先读长度,再读对应字节数转成字符串,完全不需要分隔符,也避免了逗号冲突的问题。

写入示例

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.nio.charset.StandardCharsets;

public class CustomBinaryWriter {
    public static void main(String[] args) {
        ArrayList<String> dataList = new ArrayList<>();
        dataList.add("Alice");
        dataList.add("alice@example.com, test"); // 即使包含逗号也没问题

        try (FileOutputStream fos = new FileOutputStream("custom_user_data.bin")) {
            // 先写入列表元素数量(方便读取时循环)
            fos.write(intToBytes(dataList.size()));
            
            for (String s : dataList) {
                byte[] strBytes = s.getBytes(StandardCharsets.UTF_8);
                // 写入字符串字节长度
                fos.write(intToBytes(strBytes.length));
                // 写入字符串的字节内容
                fos.write(strBytes);
            }
            System.out.println("自定义格式数据写入完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 辅助方法:将int转为4字节数组(大端序)
    private static byte[] intToBytes(int value) {
        return new byte[]{
                (byte) (value >> 24),
                (byte) (value >> 16),
                (byte) (value >> 8),
                (byte) value
        };
    }
}

读取示例

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.nio.charset.StandardCharsets;

public class CustomBinaryReader {
    public static void main(String[] args) {
        ArrayList<String> loadedList = new ArrayList<>();

        try (FileInputStream fis = new FileInputStream("custom_user_data.bin")) {
            // 读取列表元素数量
            int listSize = bytesToInt(readExactBytes(fis, 4));
            
            for (int i = 0; i < listSize; i++) {
                // 读取当前字符串的字节长度
                int strLength = bytesToInt(readExactBytes(fis, 4));
                // 读取对应长度的字节并转为字符串
                byte[] strBytes = readExactBytes(fis, strLength);
                loadedList.add(new String(strBytes, StandardCharsets.UTF_8));
            }

            // 输出读取结果
            for (String field : loadedList) {
                System.out.println(field);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 辅助方法:读取指定长度的字节
    private static byte[] readExactBytes(FileInputStream fis, int length) throws IOException {
        byte[] bytes = new byte[length];
        int readBytes = fis.read(bytes);
        if (readBytes != length) {
            throw new IOException("读取字节数不足,文件可能损坏");
        }
        return bytes;
    }

    // 辅助方法:将4字节数组转为int(大端序)
    private static int bytesToInt(byte[] bytes) {
        return ((bytes[0] & 0xFF) << 24) |
               ((bytes[1] & 0xFF) << 16) |
               ((bytes[2] & 0xFF) << 8) |
               (bytes[3] & 0xFF);
    }
}

四、为什么你的逗号二进制分隔思路不推荐

用逗号的二进制值(0x2C)作为分隔符有两个致命问题:

  1. 字符串本身可能包含逗号:如果你的某个String元素里有逗号,split的时候会把一个完整的字符串拆成多个,导致数据错误。
  2. 二进制字节冲突:二进制文件里的其他字节可能巧合等于0x2C,会被误判为分隔符,破坏整个数据结构。

所以这种方法稳定性很差,不建议使用。

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

火山引擎 最新活动