[英]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. 但问题是,由于
BitSet
类right 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
有几个问题:
.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
); 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.