2009-09-04 3 views
6

У меня есть BitSet и вы хотите записать его в файл - я наткнулся на решение использовать ObjectOutputStream с помощью метода writeObject.Запись BitSet в файл в java

Я смотрел на ObjectOutputStream в Java API, и увидел, что вы можете писать другие вещи (байты, INT, короткие и т.д.)

Я пытался проверить класс, так что я пытался записать байты в файл используя следующий код, но результат дает мне файл с 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

+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

Формат сериализации, как и многие другие, включает заголовок с магическим номером и информацией о версии. При использовании методов DataOutput/OutputStream на ObjectOutputStream размещены в середине сериализованных данных (без информации о типе). Обычно это делается только в версиях writeObject после вызова defaultWriteObject или использования putFields.

0

Если вы используете только сохраненный BitSet в Java, сериализация работает нормально. Тем не менее, это раздражает, если вы хотите делиться битетом на нескольких платформах. Помимо накладных расходов на сериализацию Java, BitSet хранится в единицах 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]; 
    } 
}