我有这个应用程序,我应该大量使用BitSet
类并逐位写入文件。我知道我不能将位写入文件,所以首先我将BitSet
对象转换为字节数组并写为字节数组。但问题是BitSet
类从right to left
索引,当我将BitSet
对象转换为字节数组并写入文件时,它会向后写入。
例如,这是我的BitSet对象:
10100100
和BitSet.get(0)给出false,BitSet.get(7)给出true。我想把它写成文件,如:
00100101
所以第一位为0,最后一位为1.
我的转换方法:
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;
}
我的写法:
FileOutputStream fos = new FileOutputStream(filePath);
fos.write(BitOperations.toByteArray(cBitSet));
fos.close();
这是打算像这样还是我做错了什么?谢谢。
答案 0 :(得分:6)
BitSet
有几个问题:
.toByteArray()
在输出上提供的字节数组的长度取决于设置为1的最高位(如果没有设置则为0,如果最后一位设置为&lt; 8则为1,如果&lt为2则为2 ; 16等 - 实质上,indexOf(highestBitSet) + 7) / 8
); 考虑使用ByteBuffer
之上的包装。示例代码如下。
注意:这使用“静态工厂方法”进行构造,因此您需要使用BitFlags.withByteLength()
或BitFlags.withBitLength()
来创建新实例。当然,您可以为此设计自己的方法,或者只是将构造函数设为公共。要获取基础数组,请调用.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();
}
}
答案 1 :(得分:6)
BitSet实现Serializable。如果您只需要能够在Java中恢复BitSet,并且不需要在文件中检查其状态,那么您应该告诉它将自己保存到文件中。
如果要将其写入包含其他非序列化数据的文件,可以将其写入ByteArrayOutputStream并从中检索byte []。但是,您可能会在直接写入文件时获得更好的性能。
答案 2 :(得分:0)
这对我来说看起来很合理。它不会很快,但它应该工作。如果您希望它以相反的顺序写出位,只需反转索引和移位:
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);
}
}
甚至:
bytes[i / 8] |= 128 >> (i % 8);
如果你的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);
}
如果您需要更高的密集位集速度,可以尝试使用标准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;
}