2016-08-25 47 views
2

现在我有试图有效段的消息到部分有点例程和计算需要单独追加字符的OutputStream,通常BAOS,然后做类似byte[] packed = packData(baos)和计算从包装的尺寸大小。这个包装步骤是必要的,因为当我做baos.write(my5bitbyte)时,我正在浪费点数。在Java中,是否有内置或常见的Stream,允许输出5位数据?

所以在包装工序我通常做这样的事情:

  1. 需要一点从的baos.toByteArray()
  2. 字节设置创建一个新的位为构建字节
  3. 从每个字节设置,取0-4位,并以明显的方式将它们附加到新位集
  4. 从新的位集合中创建一个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(); 
    } 
} 
+0

没有,因为最小单位的各种协议,设备,处理器,RAM等的使用是字节。你可以只垫零字节,如果你不要;吨需要所有位 –

+0

这里真正的问题是,为什么你使用5位编码。 30年前,Baudot与Telex机器一起推出。 – EJP

+1

为什么不使用自定义FilterOutputStream中的包裹你的ByteArrayOutputStream,而这将缓冲它接收,直到他们可以结合在一起,并写入BAOS字节。 close()方法会填充最后剩余的位,如果有的话,将其写入BAOS,然后关闭BAOS。 –

回答

1

一个自然的方法是写一个单独的输出流类链(或套)另一个输出流(要链接作家,缓冲流和无缓冲流相同的方式)。

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

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位。

相关问题