繁体   English   中英

在Java中使用RandomAccessFile的文件不完整

[英]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)方法。

我会:

  1. 将RandomAccessFile更改为FileOutputStream。

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

  3. 将复制循环简化为此:

    而(((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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM