0

我做了一个小程序来下载数据并将其写入文件。

这是代码:

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。字节数组大小为 4 K。我的第二个问题是:如果线程必须等待字节数组填满,我如何测量速度(以一秒为间隔)?我的答案应该是:将字节数组大小更改为更小的值。但是文件会损坏xD。

在尝试自己解决问题后,我花了 2 天时间在互联网上搜索解决方案。没事了。

请问各位大大能回答我的两个问题吗?谢谢=D

编辑

canDownload() 的代码:

synchronized private boolean canDownload()
{
    return can_download;
}
4

3 回答 3

2

我的建议是使用经过验证的库,例如Apache Commons IO,而不是尝试编写自己的代码。对于您的特定问题,请查看copyURLToFile(URL, File)方法。

于 2012-06-13T23:55:29.947 回答
1

我会:

  1. 将 RandomAccessFile 更改为 FileOutputStream。

  2. 摆脱canDownload(),无论它是为了什么,而是在连接上设置读取超时。

  3. 将复制循环简化为:

    while ((bytes_read = i.read(bytes)) > 0) { out.write(bytes, 0, bytes_read); } out.close(); 我关上();

与此循环之外的所有异常处理。

于 2012-06-14T01:56:28.740 回答
1

我认为您会发现问题在于您关闭了底层 InputStream 而 RandomAccessFile 仍然在其写入缓冲区中有数据。这就是您偶尔会丢失最后几个字节数据的原因。

竞争条件介于 JVM 刷新最终写入和您对 i.close() 的调用之间。

删除 i.close() 应该可以解决问题;这不是必需的,因为 raf.close() 无论如何都会关闭底层流,但是这样您就可以让 RAF 有机会在它这样做之前刷新任何未完成的缓冲区。

于 2012-06-14T03:18:57.060 回答