简体   繁体   English

Java BitSet和byte []用法

[英]Java BitSet and byte[] usage

I have this application where I should use BitSet class heavily and write to a file bit by bit. 我有这个应用程序,我应该大量使用BitSet类并逐位写入文件。 I know I can't write bits to a file, so first I convert the BitSet object to byte array and write as byte array. 我知道我不能将位写入文件,所以首先我将BitSet对象转换为字节数组并写为字节数组。 But the problem is since BitSet class indexed from right to left , when I convert the BitSet object to byte array and write to a file, it writes backwards. 但问题是,由于BitSetright to left索引,当我将BitSet对象转换为字节数组并写入文件时,它向后写入。

For example this is my BitSet object: 例如,这是我的BitSet对象:

10100100

and BitSet.get(0) gives false, and BitSet.get(7) gives true. 和BitSet.get(0)给出false,BitSet.get(7)给出true。 I want to write this to file like: 我想把它写成文件,如:

00100101

so first bit will be 0 and last bit will be 1. 所以第一位为0,最后一位为1。

My convert method: 我的转换方法:

public static byte[] toByteArray(BitSet bits) 
{
    byte[] bytes = new byte[(bits.length() + 7) / 8];       
    for (int i = 0; i < bits.length(); i++) {
        if (bits.get(i)) {
            bytes[bytes.length - i / 8 - 1] |= 1 << (i % 8);
        }
    }
    return bytes;
}

My write method: 我的写法:

    FileOutputStream fos = new FileOutputStream(filePath);
    fos.write(BitOperations.toByteArray(cBitSet));
    fos.close();

Is this intended to be like this or am I doing something wrong? 这是打算像这样还是我做错了什么? Thank you. 谢谢。

BitSet has several problems: BitSet有几个问题:

  • the length of the byte array it provides on output, using .toByteArray() , depends on the uppermost bit set to 1 (0 if no bit set, 1 if the last bit set is < 8, 2 if < 16 etc -- in essence, indexOf(highestBitSet) + 7) / 8 ); 它在输出上提供的字节数组的长度,使用.toByteArray() ,取决于设置为1的最高位(如果没有设置,则为0;如果最后一位设置为<8,则为1,如果<16等,则为1等)本质, indexOf(highestBitSet) + 7) / 8 );
  • as such, you cannot rely on it for computing a bit mask of fixed length. 因此,你不能依赖它来计算固定长度的位掩码。

Consider using a wrapper over ByteBuffer instead. 考虑使用ByteBuffer的包装器。 Sample code below. 示例代码如下。

Note: this uses "static factory methods" for construction, so you will need to use either of BitFlags.withByteLength() or BitFlags.withBitLength() to create a new instance. 注意:这使用“静态工厂方法”进行构造,因此您需要使用BitFlags.withByteLength()BitFlags.withBitLength()任何一个来创建新实例。 You can, of course, devise your own methods for that or just make the constructor public. 当然,您可以为此设计自己的方法,或者只是将构造函数设为公共。 To get the underlying array, call .toByteArray() . 要获取底层数组,请调用.toByteArray()

public final class BitFlags
{
    private final int nrBytes;
    private final ByteBuffer buf;

    private BitFlags(final int nrBytes)
    {
        if (nrBytes < 1)
            throw new IllegalArgumentException("need at least one byte");
        this.nrBytes = nrBytes;
        buf = ByteBuffer.allocate(nrBytes);
    }

    public static BitFlags withByteLength(final int nrBytes)
    {
        return new BitFlags(nrBytes);
    }

    public static BitFlags withBitLength(final int nrBits)
    {
        return new BitFlags((nrBits - 1) / 8 + 1);
    }

    public void setBit(final int bitOffset)
    {
        if (bitOffset < 0)
            throw new IllegalArgumentException();

        final int byteToSet = bitOffset / 8;
        if (byteToSet > nrBytes)
            throw new IllegalArgumentException();

        final int offset = bitOffset % 8;
        byte b = buf.get(byteToSet);
        b |= 1 << offset;
        buf.put(byteToSet, b);
    }

    public void unsetBit(final int bitOffset)
    {
        if (bitOffset < 0)
            throw new IllegalArgumentException();

        final int byteToSet = bitOffset / 8;
        if (byteToSet > nrBytes)
            throw new IllegalArgumentException();

        final int offset = bitOffset % 8;
        byte b = buf.get(byteToSet);
        b &= ~(1 << offset);
        buf.put(byteToSet, b);
    }

    public byte[] toByteArray()
    {
        return buf.array();
    }
}

BitSet implements Serializable. BitSet实现Serializable。 If you only need to be able to restore the BitSet in Java, and don't need to otherwise examine its state in the file, you should just tell it to save itself to the file. 如果您只需要能够在Java中恢复BitSet,并且不需要在文件中检查其状态,您应该告诉它将自己保存到文件中。

If you wish to write it to a file that contains other, non-serialized data, you can write it to a ByteArrayOutputStream and retrieve the byte[] from that. 如果要将其写入包含其他非序列化数据的文件,可以将其写入ByteArrayOutputStream并从中检索byte []。 However, you will probably get better performance writing directly to the file. 但是,直接写入文件可能会获得更好的性能。

That looks reasonable to me. 这看起来很合理。 It won't be very fast, but it should work. 它不会很快,但它应该工作。 If you want it to write out the bits in the opposite order, just reverse the indexing and the shift: 如果您希望它以相反的顺序写出位,只需反转索引和移位:

byte[] bytes = new byte[(bits.length() + 7) / 8];       
for (int i = 0; i < bits.length(); i++) {
    if (bits.get(i)) {
        bytes[i / 8] |= 1 << (7 - i % 8);
    }
}

or even: 甚至:

        bytes[i / 8] |= 128 >> (i % 8);

If your bitset is fairly sparse (or possibly even if it isn't), only iterating over the 1 bits might be more efficient: 如果你的bitset相当稀疏(或者即使它不是),只能迭代1位可能更有效:

byte[] bytes = new byte[(bits.length() + 7) / 8];
for ( int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i+1) ) {
    bytes[i / 8] |= 128 >> (i % 8);
}

If you need more speed for dense bitsets, you could try using the standard BitSet.toByteArray() method and then use bit-twiddling tricks to reverse the bits in the individual bytes: 如果密集位集需要更高的速度, 可以尝试使用标准的BitSet.toByteArray()方法,然后使用bit-twiddling技巧来反转各个字节中的位:

byte[] bytes = bits.toByteArray();
for ( int i = 0; i < bytes.length; i++ ) {
    byte b = bytes[i];
    b = ((b & 0x0F) << 4) | ((b & 0xF0) >> 4);
    b = ((b & 0x33) << 2) | ((b & 0xCC) >> 2);
    b = ((b & 0x55) << 1) | ((b & 0xAA) >> 1);
    bytes[i] = b;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM