2011-03-06 195 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);