Как преобразовать логический массив в двоичный и наоборот в Java? - PullRequest
3 голосов
/ 19 февраля 2012

Каков наиболее эффективный способ вывода логического массива (и ввода из) файла в Java?Я собирался использовать строку с каждым символом, являющимся или 't' или 'f', и затем я подумал, почему бы не занять восемь раз меньше места?

NOTE

На самом деле я понятия не имею, какой ответ является лучшим методом, я просто выбрал метод Питера, потому что я его понимаю.Спасибо обоим ответчикам!

Ответы [ 2 ]

6 голосов
/ 19 февраля 2012

Скажем, у вас есть логическое значение []

boolean[] ar = {true,false,false,true,false,true,true,true,false,true,false,false,false,true,tr‌​ue};

и вы хотите записать это на диск, и вам все равно, как это реализовано в памяти.

public static void main(String... args) throws IOException {
    boolean[] ar = {true, false, false, true, false, true, true, true, false, true, false, false, false, true, true};

    FileOutputStream out = new FileOutputStream("test.dat");
    writeBooleans(out, ar);
    out.close();

    FileInputStream in = new FileInputStream("test.dat");
    boolean[] ar2 = new boolean[ar.length]; 
    readBooleans(in, ar2);
    in.close();

    System.out.println(Arrays.toString(ar));
    System.out.println(Arrays.toString(ar2));
    System.out.println("The file size was "+new File("test.dat").length()+" bytes.");
}

private static void writeBooleans(OutputStream out, boolean[] ar) throws IOException {
    for (int i = 0; i < ar.length; i += 8) {
        int b = 0;
        for (int j = Math.min(i + 7, ar.length-1); j >= i; j--) {
            b = (b << 1) | (ar[j] ? 1 : 0);
        }
        out.write(b);
    }
}

private static void readBooleans(InputStream in, boolean[] ar) throws IOException {
    for (int i = 0; i < ar.length; i += 8) {
        int b = in.read();
        if (b < 0) throw new EOFException();
        for (int j = i; j < i + 8 && j < ar.length; j++) {
            ar[j] = (b & 1) != 0;
            b >>>= 1;
        }
    }
}

печать

[true, false, false, true, false, true, true, true, false, true, false, false, false, true, true]
[true, false, false, true, false, true, true, true, false, true, false, false, false, true, true]
The file size was 2 bytes.

но если я посмотрим, насколько большой файл на самом деле

$ ls -l test.dat
-rw-rw-r-- 1 peter peter 2 2012-02-19 14:04 test.dat
$ du -h test.dat 
4.0K    test.dat

В нем указано, что длина составляет 2 байта, но фактически используемое дисковое пространство составляет 4 КБ.

Примечание. Около 1 минуты вашего времени стоит примерно столько же, сколько 80 МБ SSD (дорогой диск, больше для жесткого диска). Поэтому, если вы не думаете, что сэкономите по крайней мере 80 МБ, вы можете тратить свое время. ;)


Вы можете использовать BitSet, который может занимать в 16 раз меньше места, поскольку каждый символ является 16-разрядным.

5 голосов
/ 19 февраля 2012

Недавно созданный, только для вас.Я оставлю BooleanInputStream в качестве упражнения.Обратите внимание, что первый бит теперь является самым правым (MSB) битом в файле (удалите Byte.SIZE - 1 - в примере для другого порядка байтов, что вы предпочитаете).Просто используйте, например, DataOutputStream, чтобы сначала записать размер объекта в файл.10K должно уместиться в целое число.

Обратите внимание, что хранение логического массива из 10K элементов очень неэффективно с точки зрения памяти, для этого вам непременно следует использовать BitSet (наконец, кто-то, кому нужна BitSet)!

public final class BooleanOutputStream extends FilterOutputStream {

    private int bitIndex;
    private byte buffer;

    public BooleanOutputStream(final OutputStream out) {
        super(out);
    }

    public void writeBoolean(final boolean value) throws IOException {
        buffer ^= (value ? 1 : 0) << (Byte.SIZE - 1 - bitIndex++);
        if (bitIndex == Byte.SIZE) {
            write(buffer & 0xFF);
            buffer = 0;
            bitIndex = 0;
        }
    }

    /**
     * This is an encoder and does therefore not close the underlying stream.
     * Please close underlying stream separately.
     */
    public void close() throws IOException {
        if (bitIndex != 0) {
            out.write(buffer);
            buffer = 0;
            bitIndex = 0;
        }
    }
}

public class BooleanInputStream extends FilterInputStream {

    private int bitIndex;
    private byte buffer;

    public BooleanInputStream(final InputStream in) {
        super(in);
    }

    public boolean readBoolean() throws IOException {
        if (bitIndex == 0) {
            int b = read();
            if (b == -1) {
                throw new EOFException();
            }
            buffer = (byte) b;
        }

        boolean value = (buffer & (1 << (Byte.SIZE - 1 - bitIndex++))) != 0;
        if (bitIndex == Byte.SIZE) {
            bitIndex = 0;
        }
        return value;
    }

    /**
     * This is a decoder and therefore does not close the underlying stream.
     * Please close underlying stream separately.
     */    
    public void close() throws IOException {
        buffer = 0;
        bitIndex = 0;
    }
}
...