2013-04-22 44 views
11
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
ArrayList<Byte> arrayList = new ArrayList<Byte>(); 
try { 
    while (responseStream.available() > 0) { 
     arrayList.add(responseStream.readByte()); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
Iterator<Byte> iterator = arrayList.iterator(); 
byte[] bytes = new byte[arrayList.size()]; 
int i = 0; 
while (iterator.hasNext()) { 
    bytes[i++] = iterator.next(); 
} 

我的網頁應用程序的每一頁加載都會調用此代碼。它似乎運行得非常快,但有什麼可以讓這個運行速度更快嗎?編輯將InputStream轉換爲byte []的最有效方法?

- 使用字節數組輸出流

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
try { 
    int read = responseStream.read(); 
    while (read != -1) { 
     byteArrayOutputStream.write(read); 
     read = responseStream.read(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
byte[] bytes = byteArrayOutputStream.toByteArray(); 
return ok(bytes).as(response.getHeader("Content-type")); 

編輯更新時間 - 基準測試代碼

平均時間後

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
long t1 = System.nanoTime(); 

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
try { 
    int read = responseStream.read(); 
    while (read != -1) { 
     byteArrayOutputStream.write(read); 
     read = responseStream.read(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
byte[] bytes = byteArrayOutputStream.toByteArray(); 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 
return ok(bytes).as(response.getHeader("Content-type")); 
100+請求 - 46873

平均時間100之後

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream(); 
long t1 = System.nanoTime(); 

ArrayList<Byte> arrayList = new ArrayList<Byte>(); 
try { 
    while (responseStream.available() > 0) { 
     arrayList.add(responseStream.readByte()); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
    return internalServerError(); 
} 
Iterator<Byte> iterator = arrayList.iterator(); 
byte[] bytes = new byte[arrayList.size()]; 
int i = 0; 
while (iterator.hasNext()) { 
    bytes[i++] = iterator.next(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 
return ok(bytes).as(response.getHeader("Content-type")); 
+請求 - 522848

平均時間後
long t1 = System.nanoTime(); 
byte[] bytes; 
try { 
    bytes = org.apache.commons.io.IOUtils.toByteArray(responseStream); 
} catch (Exception e) { 
    return internalServerError(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2-t1); 

100+請求 - 45088的平均時間之後100+請求

long t1 = System.nanoTime(); 
byte[] bytes; 
try { 
    bytes = sun.misc.IOUtils.readFully(responseStream, -1, true); 
} catch (Exception e) { 
    return internalServerError(); 
} 

long t2 = System.nanoTime(); 
System.out.println(t2 - t1); 

- 20180

+0

嘿馬特,我讀過那篇文章。我正在尋找最大的效率。 – sissonb 2013-04-22 21:28:16

+0

如果你關心它,你應該自己測量和比較不同的實現。然而,既然你說「看起來運行得很快」,如果你想讓你的代碼運行得更快,這並不會像瓶頸一樣。 – 2013-04-22 21:30:31

+0

看看這個http://stackoverflow.com/questions/6649100/cast-wrapper-array-to-corresponding-primitive-array – 2013-04-22 21:31:01

回答

12

是。使用ByteArrayOutputStream而不是ArrayList。然後從InputStream中讀取大塊字節(不使用available(),幾乎總是從不使用),並將這些塊寫入ByteArrayOutputStream,直到read()方法返回-1。然後在您的ByteArrayOutputStream上調用toByteArray()。

您可以使用Guava的ByteStreams.toByteArray()方法,它可以完成所有這些工作,或者您可以閱讀其源代碼以更好地瞭解它是如何工作的。閱讀IO tutorial也可能有所幫助。

+0

謝謝,讓我測試一下。我也會做一些基準測試 – sissonb 2013-04-22 21:33:20

+0

'available()'返回可以無阻塞地讀取的字節數。它總是可以返回0(默認情況下會這樣做)。 – 2013-04-22 21:34:44

+0

@JBNizet謝謝。 – Supericy 2013-04-22 21:35:34

1

爲什麼?該代碼完全等同於read(byte[]),只是它對整個數據執行了兩個額外的複製步驟。你不需要這些。一個簡單的read(byte[])會快幾倍。

使用available()也是無效的。您需要整個響應,而不僅僅是可以無阻塞地讀取的部分。你需要循環。

+0

謝謝,我現在正在進行這些修復。我會在幾分鐘內顯示差異。 – sissonb 2013-04-22 21:45:52

+0

一個簡單的read()不能保證(除非這個ChannelBufferInputStream實現帶來這個保證)整個流被讀取。也許這不是你的真正意思,但你需要一個閱讀循環,直到返回-1。 – 2013-04-22 21:48:47

+0

@JBNizet同意,澄清。 – EJP 2013-04-22 21:52:09

4

Apache Commons IO IOUtils.toByteArray方法有什麼問題?爲此目的已經多年優化。

+3

嘿,我不想爲一個函數導入一個庫。 – sissonb 2013-04-22 22:04:41

+1

那麼,隨着時間的推移,你可能會在圖書館中使用更多的功能,並且有什麼危害?無論如何,它是開源的。閱讀資料來源,看看他們如何做,如果你不想要整個事情。 – bmargulies 2013-04-22 23:04:49

+0

如何使用'sun.misc.IOUtils'?它內置於Java中,但我聽說不相信Sun的圖書館。 'IOUtils.readFully(responseStream,-1,true);'雖然這給我更快的結果。也許我會放棄並使用apache commons ... – sissonb 2013-04-22 23:48:42

相關問題