java - 在 Java 中,是否有一种内置的或常见的 Stream 允许输出,比如说,5 位数据?

标签 java encoding arrays outputstream bitarray

现在我有一个小程序试图有效地将消息分成几部分,计算需要将字符单独附加到 OutputStream,通常是 BAOS,然后执行类似于 byte[] packed = packData(baos) 并根据打包大小计算大小。这个打包步骤是必要的,因为我在执行 baos.write(my5bitbyte) 时浪费了比特。

所以在打包步骤中我通常会做这样的事情:

  1. baos.toByteArray()
  2. 的字节中取出一个位集
  3. 为构造字节创建一个新的位集
  4. 从每个字节中取出位 0-4 并以明显的方式将它们附加到新的位集
  5. 从新的位集创建一个byte[],填充最后一个字节的最后一个最多 7 位

我的问题是:

是否有任何方式或诸如 BitOutputStream 之类的东西?或者类似的东西?我目前这样做的方式似乎相当愚蠢,我肯定可以更聪明地处理它,但我想知道我是否忽略了一些已经存在的东西。

编辑 在检查了 ByteArrayOutputStream 的源代码后,很明显它可以用完全相同的方式为某些 BitArrayOutputStream 实现,因为它这只是一个 byte[] 封装了一些奇特的东西,所以你可以做 boolean[]。但我认为它不存在,现在我进一步研究它,所以我的问题就变成了......

那么这是实现 BitArrayOutputStream 的合理方式吗?

class FixedLengthBitArrayOutputStream extends OutputStream {

    private boolean[][] buffer;
    private final int originalLength;
    private final int bitLength;
    private int position = 0;
    private int expansions = 0;

    FixedLengthBitArrayOutputStream(short bitLength, short length) {
        this.buffer = new boolean[length][bitLength];
        this.originalLength = length;
        this.bitLength = bitLength;
    }

    private int limitBeforeExpansion(double factor) {
        return Math.max(
                (int) Math.floor(factor * buffer.length),
                (int) Math.floor( (1 - Math.pow(factor, expansions + 1)) * buffer.length)
        );
    }

    private boolean needsExpansion() {
        return position > limitBeforeExpansion(0.8);
    }

    private void expandIfNecessary() {
        if (needsExpansion()) {
            expansions++;
            this.buffer = Arrays.copyOf(this.buffer, (int) Math.pow((double)this.originalLength, expansions + 1));
        }
    }

    public boolean[] bitValue(int number) throws IllegalStateException {

        int remainder = number;
        boolean[] bits = new boolean[this.bitLength];

        for (int i = this.bitLength - 1; i >= 0; i--) {
            int power = (int) Math.pow(2, i + 1);
            boolean value = remainder > power;
            bits[i] = value;
            if (value) {
                remainder -= power;
            }
        }

        if (remainder != 0)
            throw new IllegalStateException("whoa");

        return bits;
    }

    @Override
    public void write(int b) throws IOException, IllegalStateException {
        expandIfNecessary();

        this.buffer[position] = bitValue(b);
        position++;
    }

    public byte[] toByteArray() {

        BitSet bitSet = new BitSet(this.position * this.bitLength);

        for (int i = 0; i < position; i++) {
            boolean[] bits = this.buffer[i];

            for (int j = 0; j < bits.length; j++) {
               bitSet.set( i * bits.length + j , bits[j] ); 
            }
        }

        return bitSet.toByteArray();
    }
}

最佳答案

一种自然的方法是编写一个单独的输出流类来链接(或包装)另一个输出流(与链接编写器、缓冲流和非缓冲流的方式相同)。

代码可能与此类似。我缓冲了几位直到它达到一个完整的字节并将其写入输出流。我还没有测试过。因此它可能包含一两个错误。

class PackedBitsOutputStream {

    private OutputStream outputStream;
    private int numBufferedBits;
    private byte bufferedBits;

    PackedBitsOutputStream(OutputStream os) {
        outputStream = os;
    }

    void writeBitSet(int data, int relevantBits) {
        bufferedBits = (byte) (bufferedBits | (data << bufferedBits));
        numBufferedBits += relevantBits;
        if (numBufferedBits >= 8) {
            outputStream.write(bufferedBits);
            numBufferedBits -= 8;
            bufferedBits = (byte) (data >> (relevantBits - numBufferedBits));
        }
    }

    void flush() {
        outputStream.write(bufferedBits);
        bufferedBits = 0;
        numBufferedBits = 0;
        outputStream.flush();
    }

    void close() {
        flush();
        outputStream.close();
    }
}

注意:writeBitSet 目前最多可以一次写入 8 位。

关于java - 在 Java 中,是否有一种内置的或常见的 Stream 允许输出,比如说,5 位数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39141806/

相关文章:

MySQL:带有UTF字符的表名

iphone - 使用自定义类的实例对数组进行排序

java - Android studio ConstraintLayout 调整大小问题

java - 在对话框中启用 GPS 后,Android 位置返回 null

java - 如何在不知道类名的情况下调用方法?

encoding - FFmpeg WebM AV1 支持

encoding - 如何设置WildFly 9.0.1.Final httpUri编码

javascript - 当有 2 个数组要检查或比较时使用 javascript 过滤

java - 为什么 Collection<E>#toArray() 不返回 E[]?

java - 给定一个已排序的数组(按绝对值排序)和一个数字,找到该数字的位置