2010-06-13 43 views
3

对于一个项目,我必须将二进制字符串转换为(一个数组)字节并将其写入二进制文件中。Java - 需要二进制/代码字符串操作方面的帮助

假设我使用huffman编码将一个句子转换为代码字符串。例如,如果句子是: “你好”,H = 00 E = 01,L = 10,O = 11

然后字符串表示将0001101011.

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

回答

0

如果您确实想要(或必须)创建位的字符串表示形式,则可以将字符串拆分为长度为8的子字符串(注意最后一个不必是长度为8的字符串)。

Integer 具有解析字符串表示的方法,序列“0”和“1的可通过用基数调用被解析= 2

static int parseInt(String s, int radix) 

将字符串参数作为带符号的整数基数由第二个参数指定。

-

编辑: 根据注释Byte.parseByte是要走的路。

+0

OP询问一个字节,所以Byte.parseByte(s,radix)是正确的方法。 – 2010-06-14 04:05:40

+0

@Todd,你说得对。 Byte.parseBytes已经引入JDK1.6 – stacker 2010-06-14 08:55:47

+0

'parseBytes()'? – trashgod 2010-08-19 00:53:50

0

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

从概念上讲,你所要做的是将位写入byte,直到你填满了byte。这是通过位移来完成的。要在价值的底部增加1位,你做这样的事情:

b = (b << 1) | 1; 

,然后,一旦你已经填补了一个字节,你需要增加你的输出byte[]以腾出空间给另一个,直到完成。您也可以使用ByteArrayOutputStream来稳定输出byte,稍后再获取byte[]

我可以指您a class,让您追加位,然后得到结果字节,认为它创建了一个数组int s而不是字节。你可以用它作为例子。

1

下面是一个简单的,但可能是低效的实现:

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添加到数组索引。

0

通过连接字符串表示来对字符串进行编码对代表单个字符的位序列进行bot处理,然后再将其转换为字节看起来像是一种非常昂贵的处理方式。

您可能想要考虑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' 

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

@BoundHuffmanCoded String toBeEncoded = "hello"; 

...和Preon会照顾其余的。现在请记住,这是理想的情况,Preon没有这个注释还有。但是可以自己注册一个编解码器。不过要注意它,因为这肯定会进入Preon的未来版本。