[英]Incomplete file using RandomAccessFile in java
我制作了一个小程序来下载数据并将其写入文件。
这是代码:
public void run()
{
byte[] bytes = new byte[1024];
int bytes_read;
URLConnection urlc = null;
RandomAccessFile raf = null;
InputStream i = null;
try
{
raf = new RandomAccessFile("file1", "rw");
}
catch(Exception e)
{
e.printStackTrace();
return;
}
try
{
urlc = new URL(link).openConnection();
i = urlc.getInputStream();
}
catch(Exception e)
{
e.printStackTrace();
return;
}
while(canDownload())
{
try
{
bytes_read = i.read(bytes);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
if(bytes_read != -1)
{
try
{
raf.write(bytes, 0, bytes_read);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
}
else
{
try
{
i.close();
raf.close();
return;
}
catch(Exception e)
{
e.printStackTrace();
return;
}
}
}
}
问题是,当我下载大文件时,文件末尾缺少几个字节。 我试图将字节数组的大小更改为2K,问题已解决。 但是当我下载一个更大的文件(500 MB)时,我又丢失了几个字节。 我说:“好,让我们尝试4K大小”。 然后我将字节数组的大小更改为4K。 有效! 很好,但是后来我下载了一个4 GB的文件,最后又丢失了字节! 我说“很酷,让我们尝试8K大小”。 然后我将字节数组的大小更改为8K。 工作。
我的第一个问题是:为什么会这样? (当我更改缓冲区大小时,文件不会损坏)。
好的,从理论上讲,可以通过将字节数组大小更改为更大的值来解决文件损坏的问题。 但是还有另一个问题:我如何测量大字节数组大小的下载速度(在一秒钟的间隔内)?
例如:假设我的下载速度为2 KB / s。 字节数组的大小为4K。我的第二个问题是:如果线程必须等待字节数组已满,我如何测量速度(在一秒钟的间隔内)? 我的答案应该是:将字节数组的大小更改为较小的值。 但是文件将损坏xD。
在尝试自己解决问题之后,我花了2天的时间在互联网上搜索解决方案。 没事了。
拜托,你们能回答我的两个问题吗? 谢谢= D
编辑
canDownload()的代码:
synchronized private boolean canDownload()
{
return can_download;
}
我的建议是使用成熟的库(例如Apache Commons IO),而不要尝试编写自己的代码。 对于您的特定问题,请看一下copyURLToFile(URL,File)方法。
我会:
将RandomAccessFile更改为FileOutputStream。
摆脱canDownload()
,无论它做什么用,而改为在连接上设置读取超时。
将复制循环简化为此:
而(((bytes_read = i.read(bytes))> 0){out.write(bytes,0,bytes_read); } out.close(); 我关上();
并在此循环外处理所有异常。
我认为您会发现问题是您关闭了底层InputStream,而RandomAccessFile的写缓冲区中仍然有数据。 这就是为什么您偶尔会丢失数据的最后几个字节的原因。
竞争条件介于JVM刷新最终写操作和您对i.close()的调用之间。
删除i.close()应该可以解决问题; 不必这样做,因为raf.close()仍然会关闭基础流,但是通过这种方式,您可以为RAF提供一个在刷新之前清除所有未完成的缓冲区的机会。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.