繁体   English   中英

Java - 需要二进制/代码字符串操作的帮助

[英]Java - Need help with binary/code string manipulation

对于一个项目,我必须将二进制字符串转换为(数组)字节并将其写入二进制文件。

假设我使用霍夫曼编码将句子转换为代码字符串。 例如,如果句子是:“你好”h = 00 e = 01,l = 10,o = 11

然后字符串表示为0001101011。

我如何将其转换为字节? < - 如果这个问题没有意义,那是因为我对比特/字节按位移位知之甚少,所有这些都与操纵1和0有关。

这是一个简单但可能效率低下的实现:

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class BitOutputStream extends FilterOutputStream {

  private int bits = 0;
  private int n = 0;
  private long totalBits = 0;

  public BitOutputStream(OutputStream out) {
    super(out);
  }

  private void writeSingleBit(int bit) throws IOException {
    bits = (bits << 1) | (bit & 1);
    n++;
    totalBits++;
    if (n == 8) {
      super.write(bits);
      bits = 0;
      n = 0;
    }
  }

  /**
   * Writes the <i>numberOfBits</i> lower bits of <i>bitsToWrite</i> to the
   * output stream, starting with the most significant bit.
   */
  public void writeBits(int bitsToWrite, int numberOfBits) throws IOException {
    for (int i = numberOfBits - 1; i >= 0; i--) {
      int bit = bitsToWrite >> i;
      writeSingleBit(bit);
    }
  }

  @Override
  public void write(byte[] b, int off, int len) throws IOException {
    for (int i = 0; i < len; i++)
      writeBits(b[off + i], 8);
  }

  @Override
  public final void write(int b) throws IOException {
    writeBits(b, 8);
  }

  @Override
  public final void flush() throws IOException {
    writeBits(0, (8 - n) & 0x07);
  }

  /**
   * Returns the number of bits that have been written to this bitstream.
   */
  public long getTotalBits() {
    return totalBits;
  }
}

和相应的单元测试:

import static org.junit.Assert.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.junit.Test;

public class BitOutputStreamTest {

  @Test
  public void hello() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    BitOutputStream bos = new BitOutputStream(baos);
    bos.writeBits(0x00, 2);
    bos.writeBits(0x01, 2);
    bos.writeBits(0x02, 2);
    bos.writeBits(0x02, 2);
    bos.writeBits(0x03, 2);
    assertEquals(10, bos.getTotalBits());
    bos.close();
    assertEquals(16, bos.getTotalBits());
    assertArrayEquals(new byte[] { 0x1A, (byte) 0xC0 }, baos.toByteArray());
  }
}

此代码不会输出所需的字符串表示中的位,但是当您希望稍后将它们写入基于字节的流时,这是可行的方法。

更新(2010-09-25):修复了write(byte[], int, int)方法中的错误。 我忘了补充off到阵列索引。

为什么你需要先转换成“二进制字符串”? 只需直接写入字节作为输出。

从概念上讲,您所做的是将位写入一个byte ,直到填满一个byte为止。 这是通过位移完成的。 要在值的底部添加1位,您可以执行以下操作:

b = (b << 1) | 1;

然后一旦你填满了一个字节,就需要增加输出byte[] ,以便为另一个byte[]腾出空间,直到完成为止。 你也可以使用ByteArrayOutputStream来稳定地输出byte ,然后再获得一个byte[]

我可以指向一个类 ,它允许你追加位然后在后面获得结果字节,认为它创建的是int而不是字节数组。 你可以用它作为例子。

如果你真的想要(或不得不)创建位的字符串表示,你可以在长度为8的子串中拆分字符串(注意最后一个不一定是长度为8的字符串)。

Integer有一个解析字符串表示的方法,可以通过使用radix = 2调用来解析'0'和'1'的序列。

static int parseInt(String s, int radix) 

将字符串参数解析为第二个参数指定的基数中的有符号整数。

-

编辑:根据评论Byte.parseByte是要走的路。

通过串联字符串表示来编码字符串,表示单个字符的位序列,然后再将其转换为字节似乎是一种非常昂贵的处理方式。

您可能想要查看Preon Preon首先具有BitChannel抽象功能,可以防止您不必担心自己的转移。 您可以简单地将位序列写入BitChannel。 它将在内部跟踪“位指针”,并将所有内容转换为更下游的字节。

BitChannel channel = new OutputStreamBitChannel(...);
channel.write(1, 0); // 0 = 'h'
channel.write(2, 1); // 01 = 'e'
channel.write(3, 2); // 10 = 'l'
channel.write(4, 2); // 11 = '0'

然而,理想情况下,你将能够使用前子的更高层次的抽象(前子结合),这将阻止您不必在所有处理这个自己。 它只需要你的String上的注释。

@BoundHuffmanCoded String toBeEncoded = "hello";

...而Preon将负责其余的工作。 现在,请记住,这是最理想的情况下,与前子没有这个注释 但是可以自己注册一个编解码器。 但要注意它,因为这肯定会进入未来版本的Preon。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM