Java BitSet 和 byte[] 用法

     2023-02-18     184

关键词:

【中文标题】Java BitSet 和 byte[] 用法【英文标题】:Java BitSet and byte[] usage 【发布时间】:2012-12-11 12:43:57 【问题描述】:

我有这个应用程序,我应该大量使用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();

这是故意的还是我做错了什么?谢谢。

【问题讨论】:

你如何使用这个文件?你以后用java读过它来恢复BitSet吗? 我将此文件作为字节数组读取,并在需要时将其转换为 BitSet,但使用外部二进制查看器时,它也会向后看。 【参考方案1】:

BitSet有几个问题:

它在输出上提供的字节数组的长度,使用.toByteArray(),取决于设置为 1 的最高位(如果没有设置位,则为 0,如果最后一个位设置为 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();
    

【讨论】:

是的,这真的很烦人。所以我创建了一个扩展 BitSet 类的 CustomBitSet 类,并添加了一个数据字段 (int) 来保存 BitSet 的实际长度,所以现在我可以使用错误的位值开始和结束我的 BitSet 对象。但这不是问题所在。 好吧,通过我的解决方案,您可以两全其美,因为您可以获得可靠的byte[] 来编写。正如我所说,如果您愿意,我可以提供示例代码。例如,我已经这样做了,用于在 DNS 标头中设置标志(标志部分位于两个字节上)。 谢谢!我去看看!【参考方案2】:

BitSet 实现了可序列化。如果您只需要能够在 Java 中恢复 BitSet,并且不需要检查其在文件中的状态,您应该告诉它自己保存到文件中。

如果您希望将其写入包含其他非序列化数据的文件,您可以将其写入 ByteArrayOutputStream 并从中检索 byte[]。但是,直接写入文件可能会获得更好的性能。

【讨论】:

【参考方案3】:

我觉得这很合理。它不会很快,但它应该工作。如果您希望它以相反的顺序写出位,只需反转索引和移位即可:

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

如果您的位集相当稀疏(或者即使不是),则仅迭代 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() 方法,然后使用位旋转技巧来反转各个字节中的位:

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;

【讨论】:

这个应用程序将在智能手机和智能电视上运行,所以你认为只迭代真实位会更有效吗?我的 BitSet 是一半 0 一半 1 等间隔分布。 可能是。请参阅编辑以获取替代方法。您可能想要对两者进行基准测试(以及其他答案中建议的解决方案)。

bitset用法

bitset了以容纳任意个数个位,并提供各项操作一、初始化bitset<16>b1; bitset<16>b2(25); bitset<16>b3(str,2,16);16表示有16位,不足的高位补0二、容量b1.size();也就是16b1.count();1的个数三、位判断b1.any();判断是否有1b1.none();判断是... 查看详情

黑科技bitset用法mark

https://www.cnblogs.com/RabbitHu/p/bitset.html 查看详情

浅析c++bitset的用法(代码片段)

浅析c++bitset的用法总述C++的\\(bitset\\)位于<bitset>头文件中,这是一种类似于数组的数据结构,每个位置存储\\(0\\or\\1\\),并且每个元素仅用\\(1\\bit\\)的空间如果换一种方式来想,\\(bitset\\)就是一个封装了一堆奇奇怪怪操作并... 查看详情

为啥 Java `BitSet` 没有 `shiftLeft` 和 `shiftRight` 函数?

】为啥Java`BitSet`没有`shiftLeft`和`shiftRight`函数?【英文标题】:WhydoesJava`BitSet`nothave`shiftLeft`and`shiftRight`functions?为什么Java`BitSet`没有`shiftLeft`和`shiftRight`函数?【发布时间】:2012-02-2411:08:46【问题描述】:这些缺失有什么特别的原... 查看详情

ggreaterandgreater(求满足条件的子序列,bitset用法)(代码片段)

...置代表一个合法子数组(因为长度固定为m);   设bitset 的ans和tmp,其中tmp为1的位置表示,对于当前的bi,a数组中有哪些比b[i].val大;    查看详情

char和byte是一个意思?

差别在哪里用法差别在哪里大家回答的详细点呀。。100分哦。。。char和byte这两种数据类型容易相互混淆,他们的区别主要如下:1、数据类型不同byte 是字节数据类型 ,是有符号型的,可以表示-128—127 的数;char ... 查看详情

java中bitset

Java中BitSet就是“位图”数据结构,根据“位图”的语义,数据的存在性可以使用bit位上的1或0来表示;一个bit具有2个值:0和1,正好可以用来表示false和true。对于判断“数据是否存在”的场景,我们通常使... 查看详情

switchcase语句的用法

Java语言switch支持部分基本数据类型(primitivedatatypes),如:byte、short、int、long、char;不支持boolean、float、double。如图的例子:2支持Enum类型、String、和部分基本类型的包装类(如:Character、Byte、Short、Integer);如图的例子:3break... 查看详情

java中outputstream中方法write用法

我在代码中有时看到OUTPUTSTREAM用WRITE方法的时候,把STRING转换成BYTE写出.我原本以为WRITE里面只能放BYTE用来写出.但后来看到有中文子的他也直接用STRING而没有转换成BYTE,这是为什么呢?write(byte[]b)方法:将b.length个字节从指定字节数... 查看详情

Java 位集示例

】Java位集示例【英文标题】:JavaBitSetExample【发布时间】:2012-03-0904:09:41【问题描述】:我正在寻找一个很好的JavaBitSet示例来处理0和1。我尝试查看Javadocs,但仅阅读该类就无法理解该类的用法。例如,and、or和xor方法如何作用... 查看详情

BitSet 与整数/长整数

】BitSet与整数/长整数【英文标题】:BitSettoandfrominteger/long【发布时间】:2011-01-2905:42:33【问题描述】:如果我想对一个整数执行位操作,如何将它加载到java.util.BitSet中?如何将其转换回int或long?我不太关心BitSet的大小——它总... 查看详情

c语音键盘钩子和用法模拟键盘

#include<windows.h>void main(){ /* 函数原型 VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, DWORD dwExtraInfo );*/ & 查看详情

[c++]用bitset代替bool数组的性能测试以及bitset的基本使用(代码片段)

文章目录bitset介绍使用¶头文件¶指定大小¶构造函数¶运算符¶成员函数¶应用¶算法样例题bitset与埃氏筛结合埃氏筛速度测试bitset介绍std::bitset是标准库中的一个存储0/1的大小不可变容器。严格来讲,它并不属于STL。bitset并不... 查看详情

Python 相当于 Java 的 BitSet

】Python相当于Java的BitSet【英文标题】:PythonequivalenttoJava\'sBitSet【发布时间】:2011-04-2603:44:06【问题描述】:是否有实现类似于BitSet的结构的Python类或模块?【问题讨论】:对于非Java程序员,什么是BitSet?你想达到什么目的?即... 查看详情

bitset是个好东西

顾名思义,就是位集合(bitset),是从JDK1.0就出现的东西,后面的版本又慢慢强化。我们说学习一样东西,最好是场景驱动-要考虑它的使用场景,这样才有意义。那么,BitSet的应用场景是什么?我个人的体会是,用于统计,统... 查看详情

delphi7:数据类型byte和word

...判断下,shl是向左移位。事实证明以上猜想正确,其正确用法为MakeWord(低八位,高八位)。※备注一:运算符or的用法※备注二:运算符shl的用法 查看详情

java中byte和byte的区别?

...是Object而byte不是对象,就只能把Byte添加进去参考技术A在java中有基本类型和复杂类型之分,byte是基本类型,是编译器可以直接识别的,属于java语法方面的而Byte是一个java包中的一个类,编译器不认识Byte他看到的是一个用户自己... 查看详情

Java:计算 java.util.BitSet 中设置的位数

】Java:计算java.util.BitSet中设置的位数【英文标题】:Java:Countnumberofbitssetinajava.util.BitSet【发布时间】:2011-06-2011:16:25【问题描述】:除了通常的“保留计数器”方法之外,还有什么快速计算BitSet中设置位数的方法吗?【问题讨... 查看详情