2011-03-06 125 views
0

考慮下面的示例代碼:下載Java中的文件 - 很慢

somefile = new URL("http://somefile.rar"); 
ReadableByteChannel rbc = Channels.newChannel(somefile.openStream()); 
FileOutputStream fos = new FileOutputStream("test"); 
long start = System.currentTimeMillis(); 
fos.getChannel().transferFrom(rbc, 0, 1 << 24); 
long end = System.currentTimeMillis(); 
System.out.println(end-start); 

問題中的文件是14MB。當我使用上面的代碼下載它時,每次需要26-30秒。我注意到,從java下載它時,有些時期根本沒有傳輸字節。當我從例如瀏覽器下載相同的文件時,它會在4秒或更短的時間內下載。任何想法是什麼問題在這裏?

回答

1

使用信道是一個不錯的主意,因爲你可以用這種方式避免了內存中的數據複製是多餘的。但是您在這裏使用的不是真正的套接字通道,而是來自URL的InputStream周圍的封裝通道,這會破壞您的體驗。

您可能可以使用SocketChannel自己實現HTTP協議,或者查找某個允許這樣做的庫。 (但是,如果結果是使用分塊編碼發送的,那麼您仍然必須自己解析它。)

所以,更簡單的方法是簡單地使用其他答案給出的通常的流複製方式。

3

我從來沒有見過這種下載方式。也許你應該嘗試用BufferedInputStream

URL url = new URL("http://yourfile.rar"); 
File target = new File("package.rar"); 
BufferedInputStream bis = new BufferedInputStream(url.openStream()); 
try { 
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(target)); 
    try { 
     byte[] buffer = new byte[4096]; 
     int bytesRead = 0; 
     while ((bytesRead = bis.read(buffer)) != -1) 
     { 
      bos.write(buffer, 0, bytesRead); 
     } 
     bos.flush(); 
    } 
    finally { 
     bos.close(); 
    } 
} 
finally { 
    bis.close(); 
} 
1

一個建議 - 爲什麼不嘗試刪除頻道,只與流工作。例如,你可以使用commons-io的

IOUtils.copy(new BufferedInputStream(somefile.openStream()), 
     new BufferedOutputStream(fos)); 
// of course, you'd have to close the streams at the end. 
0

一個更好的方式來使用普通-io的下載文件:

FileUtils.copyUrlToFile(URL url, String destination);