2010-02-19 120 views
30

我試圖從URL(使用java包 java.net.URL)讀取圖像爲byte []。 「一切」工作正常,除了內容沒有被從流中完整地讀取(圖像已損壞,它不包含所有圖像數據)...字節數組正在持久化在數據庫(BLOB)中。我真的不知道正確的做法是什麼,也許你可以給我一個提示:)java.net.URL將流讀取到byte []

這是我的第一種方法(格式化代碼,刪除不必要信​​息...):

URL u = new URL("http://localhost:8080/images/anImage.jpg"); 
int contentLength = u.openConnection().getContentLength(); 
Inputstream openStream = u.openStream(); 
byte[] binaryData = new byte[contentLength]; 
openStream.read(binaryData); 
openStream.close(); 

我的第二個方法這是一個(你會看到CONTENTLENGTH正在獲取另一種方式):

URL u = new URL(content); 
openStream = u.openStream(); 
int contentLength = openStream.available(); 
byte[] binaryData = new byte[contentLength]; 
openStream.read(binaryData); 
openStream.close(); 

無論是在損壞的圖像的代碼的結果...... 我已經閱讀這篇文章from stackoverflow

回答

51

無法保證您提供的內容長度實際上是正確的。嘗試一些類似於如下:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
InputStream is = null; 
try { 
    is = url.openStream(); 
    byte[] byteChunk = new byte[4096]; // Or whatever size you want to read in at a time. 
    int n; 

    while ((n = is.read(byteChunk)) > 0) { 
    baos.write(byteChunk, 0, n); 
    } 
} 
catch (IOException e) { 
    System.err.printf ("Failed while reading bytes from %s: %s", url.toExternalForm(), e.getMessage()); 
    e.printStackTrace(); 
    // Perform any other exception handling that's appropriate. 
} 
finally { 
    if (is != null) { is.close(); } 
} 

然後,您會在baos的圖像數據,從中你可以通過調用baos.toByteArray()得到一個字節數組。

這段代碼沒有經過測試(我只是寫在答案框中),但它相當接近我認爲你所追求的內容。

+27

請不要寫空的catch-阻止,即使在一個例子中!至少把'e.printStackTrace()'放在那裏!例子有成爲產品代碼的傾向,我們都必須稍後再處理。 – 2010-02-19 09:56:37

+2

你是對的;感謝您指出了這一點。我爲示例添加了更有意義的異常處理。 – RTBarnard 2010-02-19 10:02:08

+0

使用http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toByteArray(java.io.InputStream)。這會使代碼看起來更清潔。 – Adi 2010-02-19 10:12:52

1

內容長度只是一個HTTP頭。你不能相信它。只需從流中閱讀所有內容即可。

可用肯定是錯誤的。這只是可以無阻塞地讀取的字節數。

另一個問題是您的資源處理。在任何情況下都必須關閉流。嘗試/ catch /終於會做到這一點。

+0

Thx爲您的答案。我省略了代碼發佈中的try/catch。 但我怎麼知道流的確切長度?我必須分配byte [],所以我必須提供一個長度。分配一個固定的長度(比如說1024)並從一個位置讀到一個偏移量,檢查流是否包含數據,複製到一個新數組,合併所有字節[]不是最好的解決方案... – 2010-02-19 09:56:18

23

只是擴大Barnards的答案與commons-io。單獨的答案,因爲我不能在評論中格式化代碼。

InputStream is = null; 
try { 
    is = url.openStream(); 
    byte[] imageBytes = IOUtils.toByteArray(is); 
} 
catch (IOException e) { 
    System.err.printf ("Failed while reading bytes from %s: %s", url.toExternalForm(), e.getMessage()); 
    e.printStackTrace(); 
    // Perform any other exception handling that's appropriate. 
} 
finally { 
    if (is != null) { is.close(); } 
} 

http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toByteArray(java.io.InputStream)

+0

這是另一個不錯的解決方案,但我會使用第一個(因爲我們不會包含太多的外部庫) – 2010-02-19 10:36:08

9
byte[] b = IOUtils.toByteArray((new URL()).openStream()); //idiom 

注意然而,該流沒有在上面的例子中關閉。

如果你想有一個(76個字符)塊(使用公共編解碼器)...

byte[] b = Base64.encodeBase64(IOUtils.toByteArray((new URL()).openStream()), true); 
+6

-1不適當的格式和一點褻瀆 – asgs 2011-04-03 13:03:28

16

這裏有一個乾淨的解決方案:

private byte[] downloadUrl(URL toDownload) { 
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 

    try { 
     byte[] chunk = new byte[4096]; 
     int bytesRead; 
     InputStream stream = toDownload.openStream(); 

     while ((bytesRead = stream.read(chunk)) > 0) { 
      outputStream.write(chunk, 0, bytesRead); 
     } 

    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 

    return outputStream.toByteArray(); 
} 
+5

不要忘記調用'流'釋放使用的資源。 – 2015-06-23 19:01:46

7

我很驚訝的是,沒有人在這裏提到連接和讀取超時的問題。它可能發生(特別是在Android和/或一些蹩腳的網絡連接),請求將掛起並永遠等待。

以下代碼(也使用Apache IO Commons)將此考慮在內,並等待最大值。5秒直到它失敗:

public static byte[] downloadFile(URL url) 
{ 
    try { 
     URLConnection conn = url.openConnection(); 
     conn.setConnectTimeout(5000); 
     conn.setReadTimeout(5000); 
     conn.connect(); 

     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     IOUtils.copy(conn.getInputStream(), baos); 

     return baos.toByteArray(); 
    } 
    catch (IOException e) 
    { 
     // Log error and return null, some default or throw a runtime exception 
    } 
}