2015-04-03 51 views
0

我有點困惑,最好的方法來做到這一點。我在這裏見過很多例子,許多答案都有不同的解決方案。所以我想知道最有效的方式來寫一個很長的字符串到一個新的HTML文件(即從一個字符串創建一個HTML文件)。它真的被優先包裝成緩衝區?像:寫一個長的字符串到一個HTML文件,InputStream vs FileWriter vs BufferedReader

fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
    bufferWritter = new BufferedWriter(fileWriter); 
    bufferWritter.append(htmlContent); 

或者我可以代替做(而不丟失服務表現)

fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
    fileWriter .append(htmlContent); 

..

這是我一直在使用了一段時間的方法:

//Will run out of memory if i dont split the string in 650000 chunks 
    String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/650000)); 
    OutputStream outputStream = null; 
    InputStream inputStream = null; 

    try { 
     outputStream = new FileOutputStream(new File(dir, appBook.getPath())); //.html path 
     for (String text : bookPieces) { 
      byte[] theBytes = text.getBytes(Charset.forName("UTF-16")); 
      inputStream = new ByteArrayInputStream(theBytes); 
      byte[] bufferData = new byte[1024]; 
      int bytesRead = inputStream.read(bufferData); 

      while (bytesRead != -1) { 
       outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file" 
       bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1 
      } 
      //need to GC the inputsteam myself!!!! 
      inputStream = null; 

     } 
     toReturn = true; 

    } 

比我讀,它是優先使用BufferedReader長文本字符串。所以我改爲:

String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/650000)); 
    OutputStream outputStream = null; 
    InputStream inputStream = null; 

    OutputStreamWriter oo; 

    try { 
     outputStream = new FileOutputStream(new File(dir, appBook.getPath())); 
     for (String text : bookPieces) { 

      byte[] theBytes = text.getBytes(Charset.forName("UTF-16")); 
      inputStream = new ByteArrayInputStream(theBytes); 

      InputStreamReader iReader = new InputStreamReader(inputStream,Charset.forName("UTF-16")); 
      BufferedReader bufferedReader = new BufferedReader(iReader); 

      oo = new OutputStreamWriter(outputStream); 

      String nextLine; 

      while ((nextLine = bufferedReader.readLine())!=null) { 
       oo.write(nextLine); 
      } 
      //need to GC the inputsteam myself!!!! 
      inputStream = null; 

     } 

但我不能讓與方式的編碼正確的,一些字符會有所不同,如「 - 」變爲「€」。而且我仍然需要將字符串分成大塊,所以我沒有看到改變的目的(我是否以錯誤的方式實現了這個?),請告訴我用bufferedReader做到這一點的正確方法)。

...而且,我終於找到了兩種方法,它們的速度更快,甚至不要求我將字符串分成許多塊。

String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/100)); 
    FileWriter fileWriter = null; 
    BufferedWriter bufferWritter = null; 
    try { 
     fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
     bufferWritter = new BufferedWriter(fileWriter); 

     //Has to append, if write than OOM. 
     bufferWritter.append(htmlContent); 

     toReturn = true; 

    } 

//而且比具有編碼其slighltly比上述

//Need to split large strings in 100 chuncks 
    String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/100)); 
    BufferedWriter bufferWritter = null; 
    OutputStreamWriter osw= null; 
    try { 
     // Create osw and assign it an Encoding 
     osw = new OutputStreamWriter(
       new FileOutputStream(new File(dir, appBook.getPath())), 
       Charset.forName("UTF-16")); 
     bufferWritter = new BufferedWriter(osw); 
     for (String text : bookPieces) { 
      bufferWritter.write(text); //write faster than append here 
     } 

     toReturn = true; 

    } 
+0

'寫()'不低於'追加快'(),你不 '需要GC輸入流[你]自我'。當方法退出時,它是一個局部變量超出範圍,並自動進行GC'd。無論如何,調零參考變量不一定會導致GC。 – EJP 2015-04-03 23:17:31

+0

只是在類似的問題上閱讀你的答案,幫助我分割字符串:)。如果我不作InputStream的空我會得到OOM錯誤:/,所以它必須在堆揮之不去的地方(如果說有什麼區別的Android手機上運行它)。 – user3711421 2015-04-03 23:21:39

+0

嗯,我站在糾正,只是試了一下,並將其設置爲null沒有任何區別。然而之前,這個小變化讓我從OOME出於某種原因阻止了我,一定是別的。但是,這些方法哪一個最好。我應該將它包裝在緩衝區中嗎? – user3711421 2015-04-03 23:33:33

回答

1

這是寫代碼的簡單,還更高性能的方式,IMO較慢:

int buffSize = Math.min(65536, htmlContent.length()); 
try (Writer osw = new OutputStreamWriter(
      new FileOutputStream(new File(dir, appBook.getPath())), 
      Charset.forName("UTF-16")); 
    BufferedWriter bw = new BufferedWriter(osw, buffSize)) { 
    bw.write(htmlContent); 
} 

備註代碼:

  1. 此版本不分割文本。 BufferedWriter.write(String)代碼取決於BufferedWriter的緩衝區大小,提取,轉換並寫出塊中的字符串字符。做你自己的大塊頭是嘮叨的。

  2. 該版本根據正在寫入的字符串的大小設置BufferedWriter的緩衝區大小。但超過一定的規模(65K是猜測),通過增加緩衝區大小不會獲得任何性能優勢。

  3. 該版本使用「試用資源」來防止資源泄漏。


進一步的想法。

使用NIO可以獲得更多性能。

它可能會通過使用討厭反射訪問String對象的private字符數組,以獲得更高的性能。 (不要這樣做,這是一個壞主意!)

一個更好的辦法可能是不組裝HTML作爲一個巨大的字符串。相反,將組成HTML的字符/字符串直接寫入BufferedWriter。這避免了在同一時間容納整個HTML在內存中。


1 - 假設你使用的是StringBuilder沒有良好的尺寸暗示,你將需要多達3N的char[]字符如果你有一個很好的尺寸暗示組裝尺寸N的字符串,你只需要2N個字符...

+0

我不認爲我理解你的觀點,儘管他們可能很好。我不明白如何在你的代碼中使用buffSize?我從webview中提取所有文本(這是htmlContent),而不是使用該文本創建新的網頁。試着用REQ API 19還:( – user3711421 2015-04-04 00:16:10

+0

更正錯誤。看看現在?有關不組塊的東西,你需要看的'BufferedWriter.write'的源代碼,看看它調用。 – 2015-04-04 01:00:40

+0

*「和我正在提取網頁視圖中的所有文本(這是htmlContent)比我創建的文本新的網頁「。* - 這並不一定意味着你不能流中的數據...沒有緩衝它作爲一個字符串。這取決於你準備付出多少努力。 – 2015-04-04 01:03:10

相關問題