1. 程式人生 > >Java 按位讀取寫入檔案

Java 按位讀取寫入檔案

在實現Huffman樹時,壓縮和解壓需要從檔案中按位讀取,即一次只讀一個位或者寫一個位。
《演算法(第四版)》中提供了一種實現方法,StdIn類和StdOut類,豁然開朗。

按位讀取

方法:
1. 開闢一個緩衝區int buffer,用於儲存位,並記錄緩衝區中bit數n
2. 緩衝區不為空時,進行位運算buffer>>(n-1),即為buffer中的最高位,實現讀取一個位的操作

例:

buffer(二進位制表示) 11001010
n 8

buffer向右移7個位buffer >> (8-1),即可得到最高位1

public
static boolean readBoolean() { if (isEmpty()) throw new NoSuchElementException("Reading from empty input stream"); n--; boolean bit = ((buffer >> n) & 1) == 1; if (n == 0) fillBuffer(); return bit; }

其他部分實現

public final class BinaryStdIn {
    private static BufferedInputStream in = new
BufferedInputStream(System.in); private static final int EOF = -1; // end of file private static int buffer; // one character buffer private static int n; // number of bits left in buffer // static initializer static { fillBuffer(); } // don't instantiate
private BinaryStdIn() { } private static void fillBuffer() { try { buffer = in.read(); n = 8; } catch (IOException e) { System.out.println("EOF"); buffer = EOF; n = -1; } } /** * Returns true if standard input is empty. * @return true if and only if standard input is empty */ public static boolean isEmpty() { return buffer == EOF; } }

按位寫入

按位寫入的實現,主要是利用與運算|的特性:
1. 0 | n = n
2. 1 | n = 1

與按位讀取相同,我們同樣要使用一個緩衝區。

假設要寫入的位為 bit,則
1. 將buffer左移一位buffer <<= 1,空出一位存放bit
2. 如果bit為1,則 buffer = buffer | 1;如果bit為0,則buffer即為寫入bit後的緩衝區

例如:

buffer(二進位制表示) 110110
bit 1
buffer <<= 1 1101100
bit的8位二進位制表示 00000001
與運算結果 1101101

程式碼實現

private static void writeBit(boolean bit) {
    // add bit to buffer
    buffer <<= 1;
    if (bit) buffer |= 1;
    // if buffer is full (8 bits), write out as a single byte
    n++;
    if (n == 8) clearBuffer();
} 

完整實現

public final class BinaryStdOut {
    private static BufferedOutputStream out = new BufferedOutputStream(System.out);

    private static int buffer;     // 8-bit buffer of bits to write out
    private static int n;          // number of bits remaining in buffer

    // don't instantiate
    private BinaryStdOut() { }

   /**
     * Write the specified bit to standard output.
     */
    private static void writeBit(boolean bit) {
        // add bit to buffer
        buffer <<= 1;
        if (bit) buffer |= 1;

        // if buffer is full (8 bits), write out as a single byte
        n++;
        if (n == 8) clearBuffer();
    } 

    private static void clearBuffer() {
        if (n == 0) return;
        if (n > 0) buffer <<= (8 - n);
        try {
            out.write(buffer);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        n = 0;
        buffer = 0;
    }