2009-09-04 6 views
6

Ich habe ein BitSet und möchte es in eine Datei schreiben- Ich stieß auf eine Lösung, um einen ObjectOutputStream mit der Methode writeObject zu verwenden.Schreiben eines BitSet in eine Datei in Java

schaute ich auf der Object in dem Java-API und sah, dass Sie andere Dinge schreiben können (Byte, int, kurz etc.)

Ich habe versucht, die Klasse zu überprüfen, so dass ich versuchte, einen Byte in eine Datei zu schreiben mit dem folgenden Code, aber das Ergebnis gibt mir eine Datei mit 7 Bytes anstelle von 1 Byte

meine Frage ist, was sind die ersten 6 Bytes in der Datei? Warum sind die hier?

meine Frage ist relevant für ein BitSet, weil ich nicht beginnen möchte, viele Daten in eine Datei zu schreiben und erkennen, dass ich zufällige Bytes in die Datei eingefügt habe, ohne zu wissen, was sie sind.

hier ist der Code:

byte[] bt = new byte[]{'A'}; 
    File outFile = new File("testOut.txt"); 
    FileOutputStream fos = new FileOutputStream(outFile); 
    ObjectOutputStream oos = new ObjectOutputStream(fos); 
    oos.write(bt); 
    oos.close(); 

Dank für jede Hilfe

Avner

Antwort

2

Die anderen Bytes sind Typinformationen.

Im Grunde ist ObjectOutputStream eine Klasse, die verwendet wird, um serialisierbare Objekte in ein Ziel (normalerweise eine Datei) zu schreiben. Es macht mehr Sinn, wenn Sie an InputObjectStream denken. Es hat eine readObject() -Methode. Woher weiß Java, welches Objekt instanziiert werden soll? Ganz einfach: Da ist Typinformation drin.

+0

Also wenn ich dich richtig verstehe - jedes Mal, wenn ich etwas mit ObjectOutputStream schreibe, bekomme ich einen ernsthaften Overhead für jeden Schreibvorgang. zum Beispiel, wenn ich ein int, ein kurzes, ein Byte und dann eine Zeichenfolge schreiben Ich bekomme 4 Sätze von zusätzlichen Daten für jedes Element, das ich schreibe? – Avner

+2

Nein. Nur die Methode writeObject() fügt den Typheader hinzu. Die Methode writeUTF() fügt ein 2 Byte langes Präfix hinzu. Die primitiven writeXX() - Methoden fügen keinen Overhead hinzu. Lesen Sie das API-Dokument für Details. –

+1

Beachten Sie auch, dass die Typinformationen per-Objekt sind. Bei einem Objekt, das im Wesentlichen aus einem primitiven Array besteht (z. B. BitSet), ist der Overhead konstant, unabhängig davon, wie groß das Array ist. –

1

Sie alle Objekte aus zu einem ObjectOutputStream werden konnte schreiben, so dass der Strom enthält Informationen über die schriftlichen Typen als sowie die Daten, die zur Rekonstitution des Objekts benötigt werden.

Wenn Sie wissen, dass der Strom immer einen BitSet enthält, keine ObjectOutputStream verwenden - und wenn der Platz eine Prämie ist, dann die BitSet auf einen Satz von Bytes konvertieren, wobei jedes Bit auf ein Bit in den BitSet entspricht, schreibe das dann direkt in den zugrunde liegenden Stream (zB eine wie in deinem Beispiel).

+0

Leider hat BitSet keine integrierte Methode, um es in ein Array von Bytes zu konvertieren. – finnw

+0

Es gibt die Methode: 'toByteArray()' – clankill3r

+0

@ clankill3r: Ja, zusammen mit 'toLongArray()', aber nur seit Java 7. – charlie

0

Das Serialisierungsformat enthält, wie viele andere auch, eine Kopfzeile mit magischer Nummer und Versionsinformationen. Wenn Sie DataOutput/OutputStream verwenden, werden die Methoden ObjectOutputStream in der Mitte der serialisierten Daten platziert (ohne Typinformationen). Dies wird typischerweise nur in writeObject Implementierungen nach einem Anruf an defaultWriteObject oder Verwendung von putFields durchgeführt.

0

Wenn Sie nur das gespeicherte BitSet in Java verwenden, funktioniert die Serialisierung einwandfrei. Es ist jedoch ärgerlich, wenn Sie das Bitset auf mehrere Plattformen verteilen möchten. Neben dem Overhead der Java-Serialisierung wird das BitSet in Einheiten von 8 Bytes gespeichert. Dies kann zu viel Overhead generieren, wenn Ihr Bitset klein ist.

Wir haben diese kleine Klasse geschrieben, so dass wir Byte-Arrays aus BitSet extrahieren können. Abhängig von Ihrem Anwendungsfall funktioniert es möglicherweise besser als die Java-Serialisierung für Sie.

public class ExportableBitSet extends BitSet { 

    private static final long serialVersionUID = 1L; 

    public ExportableBitSet() { 
     super(); 
    } 

    public ExportableBitSet(int nbits) { 
     super(nbits); 
    } 

    public ExportableBitSet(byte[] bytes) { 
     this(bytes == null? 0 : bytes.length*8);   
     for (int i = 0; i < size(); i++) { 
      if (isBitOn(i, bytes)) 
       set(i); 
     } 
    } 

    public byte[] toByteArray() { 

     if (size() == 0) 
      return new byte[0]; 

     // Find highest bit 
     int hiBit = -1; 
     for (int i = 0; i < size(); i++) { 
      if (get(i)) 
       hiBit = i; 
     } 

     int n = (hiBit + 8)/8; 
     byte[] bytes = new byte[n]; 
     if (n == 0) 
      return bytes; 

     Arrays.fill(bytes, (byte)0); 
     for (int i=0; i<n*8; i++) { 
      if (get(i)) 
       setBit(i, bytes); 
     } 

     return bytes; 
    } 

    protected static int BIT_MASK[] = 
     {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; 

    protected static boolean isBitOn(int bit, byte[] bytes) { 
     int size = bytes == null ? 0 : bytes.length*8; 

     if (bit >= size) 
      return false; 

     return (bytes[bit/8] & BIT_MASK[bit%8]) != 0; 
    } 

    protected static void setBit(int bit, byte[] bytes) { 
     int size = bytes == null ? 0 : bytes.length*8; 

     if (bit >= size) 
      throw new ArrayIndexOutOfBoundsException("Byte array too small"); 

     bytes[bit/8] |= BIT_MASK[bit%8]; 
    } 
}