4

What is the most efficient way to output a boolean array to (and input from) a file in Java? I was going to use a string with each character being either 't' or 'f' and then I thought, why not take eight time less space?

NOTE

I actually have no idea which answer is the better method, I've just chosen Peter's because I understand it. Thanks to both answerers!

4
  • The general outcome will be to convert the boolean array to a byte array (where 1 bit is one boolean) and output that to file. The question then becomes how to do such a thing efficiently. Do you only have to store the bits in the file, or are you requiring a specific file format? Commented Feb 19, 2012 at 13:31
  • Hi @owlstead, thanks for your reply. no, no specific file format. the file will first indicate the size of the boolean array then the reading algorithm will use this to know how many more succeeding bytes of the file represent the array. Commented Feb 19, 2012 at 13:36
  • Interesting, that does sound like a file format. What's the maximum size (if any) of the number of booleans? Commented Feb 19, 2012 at 13:38
  • @owlstead I thought you meant an already established file format. The max size for the array is 10K (ten thousand booleans) Commented Feb 19, 2012 at 13:45

2 Answers 2

7

Say you have a boolean[]

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

and you want to write this to a disk, and you don't care how its is implemented in memory.

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;
        }
    }
}

prints

[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.

but if I look at how big the file actually is

$ 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

It says the length is 2 bytes, but the disk space used is actually 4 KB.

Note: About 1 minute of your time is worth about the same as 80 MB of SSD (expensive disk, more for HDD) So if you don't think you will be saving at least 80 MB by using this, you could be wasting your time. ;)


You can use BitSet, which can take 16x less space as each character is 16-bit.

Sign up to request clarification or add additional context in comments.

8 Comments

BitSet is not a file, please read the question before answering.
@Peter Great! could you show me how? What is the best way to store and retrieve boolean[] ar = {true,false,false,true,false,true,true,true,false,true,false,false,false,true,true}; to and from a file?
Each character is 16bit? Not on disk, it's not: depends entirely on the encoding -- and, say, UTF-8 needs only 8bits for t or f. Still I agree the concept of bitmasks is the way to go for space efficiency: length = O(n) + 1, with n the length of the boolean array.
@owlstead It doesn't say it has to be a file it says from a file which implies it is something else. Please read the question before trying to correct someone. ;)
Yeah, right :) Personally I hate BitSet as it does not provide any conversion methods. Same with EnumSet really. I've written some library functions for both which I should really send to Joshua Bloch.
|
6

Newly created, just for you. I'll leave the BooleanInputStream as an excercise. Note that the first bit is now the rightmost (MSB) bit in the file (remove Byte.SIZE - 1 - in the example for other byte order, whatever you prefer). Simply use e.g. DataOutputStream to write the size of the thing to file first. 10K should fit in an integer.

Note that storing a boolean array of 10K elements is very inefficient memory wise, you certainly should use BitSet for that (finally, somebody who needs 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;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.