2015-11-25 64 views
2

我有一個存在的問題,即使用InputStreams,我想提高從此通道讀取的性能。所以我讀了ReadableByteChannel通過ReadableByteChannel的InputStream不會結束

結果讀數與此代碼快得多:

public static String readAll(InputStream is, String charset, int size) throws IOException{ 

    try(ByteArrayOutputStream bos = new ByteArrayOutputStream()){ 
     java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(size); 

     try(ReadableByteChannel channel = Channels.newChannel(is)){ 

      int bytesRead = 0; 

      do{ 
       bytesRead = channel.read(buffer); 
       bos.write(buffer.array(), 0, bytesRead); 
       buffer.clear(); 
      } 
      while(bytesRead >= size); 
     } 
     catch(Exception ex){ 
      ex.printStackTrace(); 
     } 
     String ans = bos.toString(charset); 
     return ans; 
    } 
} 

的問題是:它不會每次讀到結尾!如果我嘗試讀取文件,它的工作原理非常好。如果我從網絡套接字讀取(例如手動請求網頁),它有時會停在兩者之間的某處。

我能做些什麼來讀到底?

我不想用這樣的:

StringBuilder result = new StringBuilder(); 
while(true){ 
    int ans = is.read(); 
    if(ans == -1) break; 
    result.append((char)ans); 
} 
return result.toString(); 

因爲這個實現是緩慢的。

我希望你能幫我解決我的問題。也許我的代碼有一些錯誤。

+1

Err ...不要使用'StringBuilder'來存儲二進制數據! – fge

+1

另外,你爲什麼認爲使用'ReadableByteChannel'會提高性能呢?簡單的'InputStream'實現已經足夠快了 – fge

+0

我之前使用了第二個實現,讀取長HTTP響應和文件的速度非常慢(不知道爲什麼)。直到現在,我只是簡單地將這種方法用於文本 - 這就是爲什麼這些方法返回一個String並使用StringBuilder。 – CHF

回答

0

你的複製循環是完全錯誤的。沒有理由爲什麼bytesRead應該有史以來>= size,並且它在流結束時行爲不當。它應該是這樣的:

while ((bytesRead = channel.read(buffer)) > 0) 
{ 
    bos.write(buffer.array(), 0, bytesRead); 
    buffer.clear(); 
} 

與適當調整限制轉移到size字節,這是不平凡的。

但是,除非因爲提前終止,否則將所有這些覆蓋在現有的InputStream之上直接使用InputStream的速度可能不會太快。除非你的想法是使用InputStream就是你發佈的內容,這太可怕了。試試用'BufferedInputStream

1

這會導致問題:

... } while (bytesRead >= size); 

從插座讀當至少一個字節讀取可以返回(或者即使在非阻擋的情況下,沒有字節)。因此,如果OS套接字緩衝區中沒有足夠的字節,該條件將會中斷循環,儘管顯然沒有讀取完整的內容。如果size標識了要接收的預期長度,則執行total += bytesRead並在total達到size時中斷循環。或者,如果你到達文件當然結束...