2009-09-04 53 views
6

我有一個BitSet並想將其寫入文件 - 我遇到了使用writeObject方法使用ObjectOutputStream的解決方案。將BitSet寫入java中的文件

我Java API中看了看ObjectOutputStream的,看到你可以寫其他的東西(一個字節,是int,short等)

我試圖檢查出類,所以我想一個字節寫入文件使用下面的代碼,但結果給我一個7字節而不是1字節的文件

我的問題是文件中的前6個字節是什麼?他們爲什麼在那裏?

我的問題與BitSet有關,因爲我不想開始將大量數據寫入文件,並意識到我在文件中插入了隨機字節而不知道它們是什麼。

這裏是代碼:

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

感謝您的幫助

阿夫納

回答

2

其他字節將是類型信息。

基本上ObjectOutputStream是一個用於將Serializable對象寫入某個目標(通常是文件)的類。如果您考慮InputObjectStream,這會更有意義。它有一個readObject()方法。 Java如何知道要實例化的對象?簡單:那裏有類型信息。

+0

所以如果我正確理解你的話 - 每次我用ObjectOutputStream寫東西時,我都會爲每次寫入產生嚴重的開銷。 例如,如果我寫一個int,一個短,一個字節,然後一個字符串 我得到4組額外的數據,我寫的每個項目? – Avner 2009-09-04 09:50:29

+2

不可以。只有writeObject()方法添加類型標題。 writeUTF()方法添加一個2字節的長度前綴。原始的writeXX()方法不會增加任何開銷。有關詳細信息,請閱讀API文檔。 – 2009-09-04 10:03:45

+1

另請注意,類型信息是每個對象。對於基本上由基本數組組成的對象(比如BitSet),無論數組多大,開銷都是恆定的。 – 2009-09-04 10:06:31

1

你可以寫任何物品運到ObjectOutputStream,所以流持有約寫的各類信息以及重構對象所需的數據。

如果你知道流將始終包含一個位集合,不使用ObjectOutputStream - 如果空間狹小,則轉換BitSet一組字節,其中每一位對應於位在BitSet,然後直接將其寫入底層流(例如,如您的示例中的FileOutputStream)。

+0

不幸的是,BitSet沒有內置方法將其轉換爲字節數組。 – finnw 2009-09-04 09:48:26

+0

有方法:'toByteArray()' – clankill3r 2015-06-22 19:35:08

+0

@ clankill3r:是的,和'toLongArray()'一起,但只有自Java 7以來。 – charlie 2016-07-04 09:27:47

0

序列化格式與許多其他格式一樣,包含一個包含幻數和版本信息的標題。當您使用DataOutput/OutputStream方法將ObjectOutputStream放置在序列化數據的中間(沒有類型信息)。這通常僅在調用defaultWriteObject或使用putFields之後的writeObject實現中完成。

0

如果您只使用Java中保存的BitSet,則序列化工作正常。然而,如果你想在多個平臺上分享這些信息,這是一件很煩人的事情。除了Java序列化的開銷之外,BitSet以8字節爲單位存儲。如果你的bitset很小,這會產生太多的開銷。

我們寫了這個小類,所以我們可以從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]; 
    } 
}