2013-03-22 15 views
0

我需要解壓二進制文件。由於二進制文件編碼爲14位,我必須讀取14位而不是8位來解碼。但據我所知,使用getc()來讀取文件只給我8位每次。有沒有任何有效的方法來實現這一目標?下面是可以完成這項工作的代碼塊,但它看起來效率不高,我該如何改進它?如何一次讀取二進制文件14位,而不是8位?

unsigned int input_code(FILE *input) 
{ 
    unsigned int return_value; 
    static int input_bit_count=0; 
    static unsigned long input_bit_buffer=0L; 

    while (input_bit_count <= 24) 
    { 
     input_bit_buffer |= 
      (unsigned long) getc(input) << (24-input_bit_count); 
     input_bit_count += 8; 
    } 

    return_value=input_bit_buffer >> (32-BITS); 
    input_bit_buffer <<= BITS; 
    input_bit_count -= BITS; 
    return(return_value); 
} 

回答

1

每個輸入/輸出char或int的指令開銷很可能會忽略不計。除非你在這裏確定瓶頸,否則不要嘗試優化這段代碼。

此外,如果我是你,我會檢查getc()返回的值。它可以返回EOF而不是數據。

而且,嚴格地說,char(或C的字節)中有CHAR_BIT位,它可以是大於8

+0

謝謝Alexey。就像你說的那樣,我無法找到一種優雅的方式來優化這段代碼。而對於EOF問題,由於文件末尾是特別編碼的,輸入將在讀取特殊代碼時結束。 – Tony 2013-03-22 23:30:19

+1

優雅的方法是*不*逐字節讀取,而是讀取更大的塊並處理它們。提示:什麼是'8 * 14'? – 2013-03-22 23:31:38

+0

@NikBougalis可能。但是我們對這個問題一無所知,有多少數據被讀取,處理它花了多少時間,所以爲什麼事先優化呢? – 2013-03-22 23:33:46

0

你不能一次讀取小於一個字節。但是,您可以使用位掩碼和移位操作將最後兩位設置爲0(如果您正在存儲16位),並將下一個值所移除的兩個未使用位進行移位。這可能會使解碼操作變得更加複雜和昂貴。

如何解碼值爲8 8(您可以讀取14個字符= 112位= 8 * 14位)?我沒有測試過這個代碼,那裏可能有一些錯別字。它編譯,但我沒有你的文件來測試它:

#include <stdio.h> 

int main(){ 
    FILE *file = fopen ("...", "rt"); 

    // loop variable 
    unsigned int i; 

    // temporary buffer 
    char buffer[14]; 

    // your decoded ints 
    int decoded[8]; 

    while(fgets(buffer, 14, file) != NULL) { 
     int cursor = 0; 

     // we do this loop only twice since the offset resets after 4 * 14 
     for(i = 0; i <= 4; i+= 4){ 
      // first decoded int is 16 bits 
      decoded[i+0] = (buffer[cursor++] | (buffer[cursor++] << 8)); 
      // second is 2 + 8 + 8 = 18 bits (offset = 2) 
      decoded[i+1] = (decoded[i+0] >> 14) | buffer[cursor++] << 2 | buffer[cursor++] << 10; 
      // third is 4 + 8 + 8 = 20 bits (offset = 4) 
      decoded[i+2] = (decoded[i+1] >> 14) | buffer[cursor++] << 4 | buffer[cursor++] << 12; 
      // next is 6 + 8 = 14 bits (offset = 6) 
      decoded[i+3] = (decoded[i+2] >> 14) | buffer[cursor++] << 6; 
     } 

     // trim the numbers to 14 bits 
     for(i = 0; i < 8; ++i) 
      decoded[i] &= ((1 << 15) - 1); 
    } 
    fclose(file); 
} 

請注意,我不這樣做與解碼的整數什麼,我一遍又一遍地寫相同的陣列上,這僅僅是一個例證。您可以更多地分解代碼,但是我展開了循環並對操作進行了評論,以便您瞭解它的工作原理。

+0

這個問題被標記爲C,而不是C++。 – 2013-03-22 23:34:10

+0

糟糕,我的壞。我刪除了此解決方案。 – Thibaut 2013-03-22 23:35:38

+0

謝謝Thibaut。我認爲原始代碼的做法與你的建議略有不同。 – Tony 2013-03-22 23:35:59

4

一般來說,您應該避免以小數量讀取數據,因爲它效率低下,儘管標準庫和O/S內的緩衝代碼將彌補這一點。

更好的原因是它會導致怪異和不自然的代碼。爲什麼不一次讀112位= 14個字節 - 這是8的倍數和14的倍數。然後可以將結果緩衝區視爲8個14位數據。所以事情很好。

但是,如果你絕對必須一次讀取的幾個字節越好,讀16位,然後吃(即工藝)的14,讀取另一個16,與2您已經閱讀它們組合起來,吃14,並重復這個過程。有關如何執行此類操作的提示,請查看base64編碼器/解碼器。

+1

當你給我8 * 14的提示時,我認爲你建議我閱讀112位。爲什麼112字節?我有點困惑。 – Tony 2013-03-22 23:49:48

+1

@tonyaziten Nik有一個聰明的主意,但他表達了錯誤。每次讀取14個字節並將它們翻譯成接下來的8個4位字。 – UncleO 2013-03-22 23:56:43

+1

@UncleO所以基本思想是我可以一次讀取8和14的最小公倍數,然後處理這些位,對嗎? – Tony 2013-03-23 00:04:45

相關問題