對於一個項目,我必須將二進制字符串轉換爲(一個數組)字節並將其寫入二進制文件中。Java - 需要二進制/代碼字符串操作方面的幫助
假設我使用huffman編碼將一個句子轉換爲代碼字符串。例如,如果句子是: 「你好」,H = 00 E = 01,L = 10,O = 11
然後字符串表示將0001101011.
我將如何轉換到這一個字節? < - 如果這個問題沒有意義,那是因爲我對比特/字節的按位移位以及與操縱1和0有關的所有知之甚少。
對於一個項目,我必須將二進制字符串轉換爲(一個數組)字節並將其寫入二進制文件中。Java - 需要二進制/代碼字符串操作方面的幫助
假設我使用huffman編碼將一個句子轉換爲代碼字符串。例如,如果句子是: 「你好」,H = 00 E = 01,L = 10,O = 11
然後字符串表示將0001101011.
我將如何轉換到這一個字節? < - 如果這個問題沒有意義,那是因爲我對比特/字節的按位移位以及與操縱1和0有關的所有知之甚少。
如果您確實想要(或必須)創建位的字符串表示形式,則可以將字符串拆分爲長度爲8的子字符串(注意最後一個不必是長度爲8的字符串)。
Integer 具有解析字符串表示的方法,序列「0」和「1的可通過用基數調用被解析= 2
static int parseInt(String s, int radix)
將字符串參數作爲帶符號的整數基數由第二個參數指定。
-
編輯: 根據註釋Byte.parseByte是要走的路。
爲什麼首先需要轉換成「二進制字符串」?只要直接寫字節作爲輸出。
從概念上講,你所要做的是將位寫入byte
,直到你填滿了byte
。這是通過位移來完成的。要在價值的底部增加1位,你做這樣的事情:
b = (b << 1) | 1;
,然後,一旦你已經填補了一個字節,你需要增加你的輸出byte[]
以騰出空間給另一個,直到完成。您也可以使用ByteArrayOutputStream
來穩定輸出byte
,稍後再獲取byte[]
。
我可以指您a class,讓您追加位,然後得到結果字節,認爲它創建了一個數組int
s而不是字節。你可以用它作爲例子。
下面是一個簡單的,但可能是低效的實現:
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
添加到數組索引。
通過連接字符串表示來對字符串進行編碼對代表單個字符的位序列進行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的未來版本。
OP詢問一個字節,所以Byte.parseByte(s,radix)是正確的方法。 – 2010-06-14 04:05:40
@Todd,你說得對。 Byte.parseBytes已經引入JDK1.6 – stacker 2010-06-14 08:55:47
'parseBytes()'? – trashgod 2010-08-19 00:53:50