2009-09-04 31 views
6

私はBitSetを持っていて、それをファイルに書きたい - 私は、writeObjectメソッドを使ってObjectOutputStreamを使う解決策を見つけました。JavaのファイルにBitSetを書き込む

私はので、私は、ファイルにバイトを書き込みしようとしたのJava APIでObjectOutputStreamのを見て、あなたは私がクラスをチェックアウトしようとした他のもの(バイト、int型、ショートなど)

を書くことができることを見ました次のコードを使用して結果が1バイトの代わりに7バイトのファイルを返します

私の質問はファイルの最初の6バイトは何ですか?なぜ彼らはそこにいますか?

私の質問は、私がファイルにたくさんのデータを書き始めたくないということと、自分が何であるか知らずにファイルにランダムなバイトが挿入されていることを認識しているからです。任意の助け

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

おかげ

Avner

答えて

2

他のバイトはタイプ情報です。

基本的にObjectOutputStreamは、いくつかの宛先(通常はファイル)にSerializableオブジェクトを書き込むために使用されるクラスです。 InputObjectStreamについて考えると、それは意味があります。そこにはreadObject()メソッドがあります。インスタンス化するオブジェクトをJavaがどのように知っていますか?簡単:そこにタイプ情報があります。

+0

私はあなたを正しく理解していれば、ObjectOutputStreamを使って何かを書くたびに、すべての書き込みに重大なオーバーヘッドが発生します。 例えば、int、short、byte、そして文字列を書くと、 は 私は書き込むアイテムごとに4セットの余分なデータを得ますか? – Avner

+2

いいえ、writeObject()メソッドのみが型ヘッダーを追加します。 writeUTF()メソッドは、2バイトのプレフィックス接頭辞を追加します。プリミティブなwriteXX()メソッドはオーバーヘッドを追加しません。詳細については、APIドキュメントをお読みください。 –

+1

また、タイプ情報はオブジェクト単位であることに注意してください。基本的にプリミティブ配列(BitSetなど)で構成されるオブジェクトの場合、配列の大きさにかかわらずオーバーヘッドは一定です。 –

1

あなたはObjectOutputStreamに出ているオブジェクトを書くことができ、その流れのように書かれたタイプに関する情報を保持している:ここ

コードですオブジェクトを再構成するために必要なデータと同様です。

あなたはストリームが常にたBitSetが含まれていることがわかっている場合は、ObjectOutputStreamを使用していない - と、スペースが貴重である場合、各ビットはBitSetのビットに対応したバイトのセットにBitSetを変換しますそのストリームに直接書き込んでください(例:FileOutputStream)。

+0

残念ながら、BitSetには、バイト配列に変換する組み込みメソッドはありません。 – finnw

+0

メソッドがあります: 'toByteArray()' – clankill3r

+0

@ clankill3r:はい、 'toLongArray()'と一緒ですが、Java 7以降のみです。 – charlie

0

他の多くと同様に、シリアル化フォーマットには、マジックナンバーとバージョン情報のヘッダーが含まれています。 ObjectOutputStreamDataOutput/OutputStreamメソッドを使用すると、シリアル化されたデータの中央に配置されます(タイプ情報なし)。これは通常、defaultWriteObjectへの呼び出しまたはputFieldsの呼び出しの後でwriteObjectの実装でのみ行われます。

0

Javaで保存したBitSetのみを使用すると、シリアル化が正常に動作します。しかし、複数のプラットフォーム間でビットセットを共有したいと思うのは厄介なことです。 BitSetは、Javaシリアル化のオーバーヘッドに加えて、8バイト単位で格納されます。ビットセットが小さければ、オーバーヘッドが大きくなります。

BitSetからバイト配列を取り出すことができるように、この小さなクラスを書きました。ユースケースによっては、Javaのシリアライズよりもうまくいくかもしれません。

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]; 
    } 
} 
関連する問題