views:

1477

answers:

4

If you have binary strings (literally String objects that contain only 1's and 0's), how would you output them as bits into a file?

This is for a text compressor I was working on; it's still bugging me, and it'd be nice to finally get it working. Thanks!

+5  A: 
Tomer Gabel
This solution uses an array of characters instead of a String object, but it could be easily modified.
Dave L.
I thought Java chars where 2 bytes wide?
Outlaw Programmer
They can be if the leading byte is a UTF8 prefix character.
Heath Borders
Why would that matter? You take characters from a string and compare them to other characters, without any conversions or decoding.
Tomer Gabel
+1  A: 

Assuming the String has a multiple of eight bits, (you can pad it otherwise), take advantage of Java's built in parsing in the Integer.valueOf method to do something like this:

String s = "11001010001010101110101001001110";
byte[] data = new byte[s.length() / 8];
for (int i = 0; i < data.length; i++) {
    data[i] = (byte) Integer.parseInt(s.substring(i * 8, (i + 1) * 8), 2);
}

Then you should be able to write the bytes to a FileOutputStream pretty simply.

On the other hand, if you looking for effeciency, you should consider not using a String to store the bits to begin with, but build up the bytes directly in your compressor.

Dave L.
BigInteger would be better. If he's storing the bits in a file, it might be greater than 32.
Heath Borders
BigInteger would fail to handle leading zeros correctly, and this method works just fine with more than 32 bits. It parses 8 at a type.
Dave L.
+2  A: 
public class BitOutputStream extends FilterOutputStream
{
    private int buffer   = 0;
    private int bitCount = 0;

    public BitOutputStream(OutputStream out)
    {
        super(out);
    }

    public void writeBits(int value, int numBits) throws IOException
    {
        while(numBits>0)
        {
            numBits--;
            int mix = ((value&1)<<bitCount++);
            buffer|=mix;
            value>>=1;
            if(bitCount==8)
                align8();
        }
    }

    @Override
    public void close() throws IOException
    {
        align8(); /* Flush any remaining partial bytes */
        super.close();
    }

    public void align8() throws IOException
    {
        if(bitCount > 0)
        {
            bitCount=0;
            write(buffer);
            buffer=0;
        }
    }
}

And then...

if (nextChar == '0')
{
    bos.writeBits(0, 1);
}
else
{
    bos.writeBits(1, 1);
}
izb
+5  A: 

If you're lucky, java.math.BigInteger may do everything for you.

String s = "11001010001010101110101001001110";
byte[] bytes = (new java.math.BigInteger(s, 2)).toByteArray();

This does depend on the byte order (big-endian) and right-aligning (if the number of bits is not a multiple of 8) being what you want but it may be simpler to modify the array afterwards than to do the character conversion yourself.

finnw
The constructor BigInteger(String) takes a base-10 argument. It should be new BigInteger(s, 2)
McDowell
You're right. Fixed, thanks.
finnw
Danger! This solution will never produce leading zeros in the output byte array, even when they belong.
Dave L.