2016-07-13 12 views
1

Ich plane, ByteArrayOutputStream verwenden, um Objekte in Byte-Array zu schreiben, dann schreibe das Byte-Array in eine Datei. Ich behalte die Position jedes Objekts. Dann lese ich mit FileInputStream.getChannel(). Position() aus der Datei, um die Position zu verschieben, und rufe ObjectInputStream.readObject() auf.Java-Serialisierung Random Access, eine sehr seltsame Sache!

Hier ist mein Testcode:

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); 
    } 

} 

Mein Problem ist, wenn der Schlüssel von "bucket2" ist das gleiche wie "bucket3" ("22313" in diesem Fall). Ich kann nicht lesen bucket3 skippet bucket2

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) 

Aber wenn der Schlüssel anders ist, kann ich dies erfolgreich tun. Es scheint, dass sich der Schlüssel von bucket3 auf die Bucket2's bezieht. das ist sehr seltsam. Und auf jeden Fall ist das sequentielle Lesen in Ordnung, aber ich möchte kein sequentielles Lesen.

Antwort

2

Ich vermute, dass ObjectInputStream einfach nicht für diese Art der Verwendung konzipiert ist. Um die referenzielle Integrität beizubehalten, vermute ich, dass es einen internen Zähler für "Objektnummer X, den ich in den Stream geschrieben habe" gibt, der beim Lesen von Objekten erhöht wird. Wenn ein Verweis auf das Objekt vorhanden ist, kann er einfach als geschrieben werden "Referenznummer X". Wenn Sie die Objekte in einer anderen Reihenfolge als in der Reihenfolge lesen, in der sie geschrieben wurden, würde dies die Dinge erheblich durcheinanderbringen.

Ich würde Ihnen dringend empfehlen, grundsätzlich nicht zu versuchen, dies zu tun. (Ich würde Ihnen auch raten, die normale Java-Binärserialisierung möglichst zu vermeiden, aber das ist eine andere Sache.)

+0

Vielen Dank für die Antwort. Was sollte ich verwenden, um den Anwendungsfall zu erreichen? Ich muss einige Objekte in Dateien schreiben und sie zufällig lesen. –

+0

Es ist schwer zu sagen, ohne mehr über die Daten zu wissen, aber vielleicht möchten Sie Ihr eigenes Format mit fester Länge. –

+0

Mein Objekt ist etwas wie der 'HashBucketTest', aber die Map ist' Map >> ', deren Größe sehr groß sein kann. –

1

Sie können dies nicht tun. Ein Objektausgabe-Stream beginnt mit einem Stream-Header und enthält Rückverweise auf bereits serialisierte Objekte. Sie können es nicht als zufällige Zugriffsfolge von einzeln serialisierten Objekten behandeln. Es ist ein Strom.