java序列化随机访问,一件非常奇怪的事情!;

java序列化随机访问,一件非常奇怪的事情!;,java,serialization,objectinputstream,Java,Serialization,Objectinputstream,我计划使用ByteArrayOutputStream将对象写入字节数组,然后将字节数组写入文件。我保持每个物体的位置。然后我从文件中读取,使用FileInputStream.getChannel().position()重新定位位置,并调用ObjectInputStream.readObject() 以下是我的测试代码: public static void main(String[] args) { try { HashBucketTest bucket1 = new

我计划使用ByteArrayOutputStream将对象写入字节数组,然后将字节数组写入文件。我保持每个物体的位置。然后我从文件中读取,使用FileInputStream.getChannel().position()重新定位位置,并调用ObjectInputStream.readObject()

以下是我的测试代码:

public static void main(String[] args) {
    try {
        HashBucketTest bucket1 = new HashBucketTest();
        bucket1.putAddress("0", 30);

        HashBucketTest bucket2 = new HashBucketTest();   // bucket2 key is the same as bucket3
        bucket2.putAddress("22313", 40);

        HashBucketTest bucket3 = new HashBucketTest();
        bucket3.putAddress("22313", 50);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oops = new ObjectOutputStream(baos);

        FileOutputStream fout = new FileOutputStream("objects.txt");
        BufferedOutputStream bs = new BufferedOutputStream(fout);

        int position1 = baos.size();                                // the first object position
        bs.write(baos.toByteArray());                               // write head
        baos.reset();

        oops.writeObject(bucket1);                  // write the first object to byte array
        int position2 = position1 + baos.size();    // the second object position
        bs.write(baos.toByteArray());               // write first object to file
        baos.reset();

        oops.writeObject(bucket2);                  // write the second object to byte array
        int position3 = position2 + baos.size();    // the third object position
        bs.write(baos.toByteArray());               // write the second object to file
        baos.reset();

        oops.writeObject(bucket3);                  // write the third object to byte array
        int position4 = position3 + baos.size();    // the fourth object position
        bs.write(baos.toByteArray());               // write the third object to file
        baos.reset();

        bs.flush();
        bs.close();
        fout.flush();
        fout.close();

        // read according to the position x

        HashBucketTest readCase1 = null;
        HashBucketTest readCase2 = null;
        HashBucketTest readCase3 = null;

        FileInputStream fis = new FileInputStream("objects.txt");
        ObjectInputStream ois = new ObjectInputStream(
                fis);

        // success case
        readCase1 = (HashBucketTest) ois.readObject();  // read the first object, success
        fis.getChannel().position(position2);
        readCase2 = (HashBucketTest) ois.readObject();  // read the second object, success
        fis.getChannel().position(position3);
        readCase3 = (HashBucketTest) ois.readObject();  // read the third object, success

        // failed case!!!!
        //readCase1 = (HashBucketTest) ois.readObject();    // read the first object, success
        //fis.getChannel().position(position3);
        //readCase3 = (HashBucketTest) ois.readObject();    // read the third object, failed!!
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static class HashBucketTest implements Serializable {

    private static final long serialVersionUID = 3610182543890121796L;

    Map<String, Integer> values = null; // need to write to disk

    public HashBucketTest() {

        values = new TreeMap<String, Integer>();
    }

    public void putAddress(String key, int number) {

        values.put(key, number);
    }

}

但是,如果关键是不同的,我可以成功地做到这一点。看来bucket3的钥匙是指bucket2的?真奇怪。在任何情况下,顺序读取都是可以的,但我不想要顺序读取。

我怀疑
ObjectInputStream
根本不适合这种用途。为了保持引用完整性,我怀疑“我已写入流的对象号X”有一个内部计数器,该计数器随着对象的读取而增加-然后当有对该对象的引用时,它可以被写入“引用号X”。当你以不同的顺序读取对象和写入对象时,会把事情搞得一团糟


我强烈建议你基本上不要这样做。(我还建议您尽可能避免常规的Java二进制序列化,但那是另一回事。)

我怀疑
ObjectInputStream
根本不适合这种用途。为了保持引用完整性,我怀疑“我已写入流的对象号X”有一个内部计数器,该计数器随着对象的读取而增加-然后当有对该对象的引用时,它可以被写入“引用号X”。当你以不同的顺序读取对象和写入对象时,会把事情搞得一团糟


我强烈建议你基本上不要这样做。(我还建议您尽可能避免常规的Java二进制序列化,但那是另一回事。)

您不能这样做。对象输出流以流头开始,并包含对已序列化对象的反向引用。不能将其视为单独序列化对象的随机访问序列。这是一条流。

你不能这样做。对象输出流以流头开始,并包含对已序列化对象的反向引用。不能将其视为单独序列化对象的随机访问序列。这是一条小溪。

谢谢您的回复。我应该使用什么来实现用例?我需要将一些对象写入文件并随机读取它们。在不了解更多数据的情况下很难说,但您可能需要自己的固定长度格式。我的对象类似于
HashBucketTest
,但映射是
map
其大小可能非常大。@hankwing:老实说,我会开始考虑改为使用数据库。实际上,我的目的是写入我计划写入文件的数据库的索引桶。谢谢你的回复。我应该使用什么来实现用例?我需要将一些对象写入文件并随机读取它们。在不了解更多数据的情况下很难说,但您可能需要自己的固定长度格式。我的对象类似于
HashBucketTest
,但映射是
map
其大小可能非常大。@hankwing:老实说,我会开始考虑改为使用数据库。实际上,我的目的是写入我计划写入文件的数据库的索引桶。无论如何谢谢你
java.io.StreamCorruptedException: invalid handle value: 007E000C
at java.io.ObjectInputStream.readHandle(ObjectInputStream.java:1456)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1331)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at java.util.TreeMap.buildFromSorted(TreeMap.java:2563)
at java.util.TreeMap.buildFromSorted(TreeMap.java:2504)
at java.util.TreeMap.readObject(TreeMap.java:2450)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1896)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1993)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1918)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.alibaba.middleware.benchmark.Test.main(Test.java:146)