我正在使用URLConnection, DataInputStream和FileOutputStream下载文件。我正在创建一个巨大的字节[]与在线文件的大小(与getContentLength())。问题是,当我尝试下载大文件时,我得到一个OutOfMemoryError: Java堆空间,这是一个正常的行为。
代码如下:
URLConnection con;
DataInputStream dis;
FileOutputStream fos;
byte[] fileData = null;
URL url = new URL(from);
con = url.openConnection();
con.setUseCaches(false);
con.setDefaultUseCaches(false);
con.setRequestProperty("Cache-Control", "no-store,max-age=0,no-cache");
con.setRequestProperty("Expires", "0");
con.setRequestProperty("Pragma", "no-cache");
con.setConnectTimeout(5000);
con.setReadTimeout(30000);
dis = new DataInputStream(con.getInputStream());
int contentLength = con.getContentLength();
//Taille connue
if (contentLength != -1)
{
fileData = new byte[con.getContentLength()];
for (int x = 0; x < fileData.length; x++)
{
fileData[x] = dis.readByte();
if (listener != null)
{
listener.onFileProgressChanged(x, fileData.length);
}
}
}
//Taille inconnue
else
{
System.out.println("Attention : taille du fichier inconnue !");
if (undefinedListener != null)
{
undefinedListener.onUndefinedFile();
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
while (true)
{
try
{
stream.write(dis.readByte());
}
catch (EOFException ex)
{
//Fin
fileData = stream.toByteArray();
stream.close();
}
}
}
dis.close();
//Ecriture
fos = new FileOutputStream(file);
fos.write(fileData);
fos.close();
我听说我应该把文件分割成块来避免它。我知道怎么做,很简单,但是…我怎么能做到这一点,如果文件的ContentLength不能从服务器(getContentLength() == -1)红色?如果我不知道文件的大小,我该如何将文件分割成块呢?
谢谢!
我正在创建一个巨大的字节[]与在线文件的大小
为什么?您不需要文件大小的字节数组。这只会浪费空间并增加延迟。只读和写入缓冲区:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
对于任何大于0的byte[]缓冲区都有效。我一般用8192
使用URLConnection,您也不需要内容长度:只需像上面那样读取到EOS。
根本没有理由使用DataInputStream
。使用Files
:
final Path dstFile = Paths.get("path/to/dstfile");
Files.copy(url.openStream(), dstFile);