2011-05-15 38 views
0

這裏是我壓縮串入一個文件:的java:d​​ecomprss文件轉換成字符串太慢

public static void compressRawText(File outFile, String src) { 
    FileOutputStream fo = null; 
    GZIPOutputStream gz = null; 
    try { 
     fo = new FileOutputStream(outFile); 
     gz = new GZIPOutputStream(fo); 
     gz.write(src.getBytes()); 
     gz.flush(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      gz.close(); 
      fo.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

這是我如何解壓縮它:

static int BUFFER_SIZE = 8 * 1024; 
static int STRING_SIZE = 2 * 1024 * 1024; 
public static String decompressRawText(File inFile) { 
    InputStream in = null; 
    InputStreamReader isr = null; 
    StringBuilder sb = new StringBuilder(STRING_SIZE);//constant resizing is costly, so set the STRING_SIZE 
    try { 
     in = new FileInputStream(inFile); 
     in = new BufferedInputStream(in, BUFFER_SIZE); 
     in = new GZIPInputStream(in, BUFFER_SIZE); 
     isr = new InputStreamReader(in); 
     char[] cbuf = new char[BUFFER_SIZE]; 
     int length = 0; 
     while ((length = isr.read(cbuf)) != -1) { 
      sb.append(cbuf, 0, length); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      in.close(); 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } 
    } 
    return sb.toString(); 
} 

減壓似乎永遠採取做。我有一種感覺,我在解壓縮位上做了太多的冗餘步驟。任何想法我可以加快它?

編輯:已經修改了代碼,基於以下給出的建議以上,
1.我chaged模式,所以簡單地我的代碼了一下,但如果我不能使用IOUtils是這個還行使用這種模式?
2.我將StringBuilder緩衝區設置爲2M,正如entonio建議的那樣,我應該將它設置得多一點嗎?內存還行,我仍然有10M左右可用,因爲它是由偏食 3.堆監視我切的BufferedReader,並添加了的BufferedInputStream建議,但我仍然不能確定BUFFER_SIZE,有什麼建議?

上述修改改進了將所有30個2M文件從30秒縮短到14個左右所需的時間,但我需要將其縮短到10個以下,甚至可以在android上執行?好吧,基本上,我需要在60M內處理一個文本文件,我已經將它們分成了30個2M,並且在我開始處理每個字符串之前,我對上述時間成本進行了上述計時,只是爲了循環所有文件並將文件中的字符串存入我的內存中。由於我沒有太多經驗,如果我使用60個1M文件,會更好嗎?或者我應該採取其他改進措施?謝謝。

另外:由於物理IO非常耗時,而且由於我壓縮的文件版本都很小(從2M文本大約2K左右),是否可以繼續執行上述操作,但是對於一個文件已經映射到內存?可能使用java的NIO?謝謝

+0

你的字符串有多大? – 2011-05-16 00:02:27

+0

除了不關閉你的輸入流(資源泄漏)和使用平臺默認字符集(有風險),我沒有看到任何代碼的主要錯誤。這個字符串有多大? (請注意,由於您已經使用數組讀取,BufferedReader在代碼中沒有用處)。 – jtahlborn 2011-05-16 00:05:47

+0

對不起,忘了提及,字符串是2M,但我在android上這樣做,我測試了它,它是可行的,但需要很長時間。我已經修復了關閉部分。 – user685275 2011-05-16 00:10:48

回答

2

BufferedReader的唯一目的是你不使用的readLine()方法,那麼爲什麼不從InputStreamReader讀取?另外,也許減小緩衝區大小可能會有所幫助。另外,您應該在讀寫時指定編碼,但不應該影響性能。

編輯:更多的數據

如果你知道字符串的大小未來,你​​應該的長度參數添加到decompressRawText並用它來初始化StringBuilder。否則,它會不斷調整大小以適應結果,這是昂貴的。

編輯:澄清

2MB意味着很多調整大小的。如果您指定的容量高於讀取後結束的容量(當然,暫時使用更多內存除外),則不會造成危害。

+0

重新調整大小 - 當StringBuilder需要擴展其內部緩衝區時,它(至少)會使數組大小加倍。這意味着*在字符串building *上分攤,字符被複制'O(1)'多餘的時間。雖然這是值得儘量避免的,但是額外複製的影響並不大。另外,如果你對未壓縮的字符串大小沒有很好的估計,你可能會由於明顯的過度分配緩衝區而導致**性能下降。 – 2011-05-16 00:55:49

+0

儘管如此,我認爲還是值得一試的,因爲它是由'entonio'建議的。由於我有2M的估計,並且在android上保存了一下是很多的。感謝評論,雖然,瞭解了很多 – user685275 2011-05-16 01:21:12

0

在打包GZipInputStream之前,您應該用BufferedInputStream包裝FileInputStream,而不是使用BufferedReader

原因在於,根據實現的不同,裝飾層次結構中的各種輸入類可能會決定逐字節讀取(我會說InputStreamReader最有可能這樣做) 。一旦達到FileInputStream,這將轉化爲許多read(2)調用。

當然,這可能只是我的迷信。但是,如果你在Linux上運行,你總是可以用strace進行測試。


編輯:一旦建立了一堆流代表當好模子,遵循的是使用單個InputStream變量。然後,您只需要在finally塊中關閉一件東西(並且可以使用Jakarta Commons IOUtils來避免大量嵌套的try-catch-finally塊)。

InputStream in = null; 
    try 
    { 
    in = new FileInputStream("foo"); 
    in = new BufferedInputStream(in); 
    in = new GZIPInputStream(in); 

    // do something with the stream 
    } 
    finally 
    { 
    IOUtils.closeQuietly(in); 
    } 
0

在FileInputStream和GZIPInputStream之間添加一個BufferedInputStream。

類似的時候寫。