简体   繁体   English

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

[英]Incomplete file using RandomAccessFile in java

I made a small program to download data and write it to a file. 我制作了一个小程序来下载数据并将其写入文件。

Here is the code: 这是代码:

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;
            }
        }
    }
}

The problem is that when I download big files, I get few bytes missing in the end of the file. 问题是,当我下载大文件时,文件末尾缺少几个字节。 I tried to change the byte array size to 2K, and the problem was solved. 我试图将字节数组的大小更改为2K,问题已解决。 But when I downloaded a bigger file (500 MB) , I got few bytes missing again. 但是当我下载一个更大的文件(500 MB)时,我又丢失了几个字节。 I said "Ok, let's try with 4K size". 我说:“好,让我们尝试4K大小”。 And I changed the byte array size to 4K. 然后我将字节数组的大小更改为4K。 It worked! 有效! Nice, but then I downloaded a 4 GB file, I got bytes missing in the end again! 很好,但是后来我下载了一个4 GB的文件,最后又丢失了字节! I said "Cool, let's try with 8K size". 我说“很酷,让我们尝试8K大小”。 And then I changed the byte array size to 8K. 然后我将字节数组的大小更改为8K。 Worked. 工作。

My first question is: Why this happens? 我的第一个问题是:为什么会这样? (when I change buffer size, the file doesn't get corrupted). (当我更改缓冲区大小时,文件不会损坏)。

Ok, in theory, the file corrupted problem can be solved changing the byte array size to bigger values. 好的,从理论上讲,可以通过将字节数组大小更改为更大的值来解决文件损坏的问题。 But there's another problem: how can I measure the download speed (in one second interval) with big byte array sizes? 但是还有另一个问题:我如何测量大字节数组大小的下载速度(在一秒钟的间隔内)?

For example: Let's say that my download speed is 2 KB/s. 例如:假设我的下载速度为2 KB / s。 And the byte array size is 4 K. My second question is: How can I measure the speed (in one second interval) if the thread will have to wait the byte array to be full? 字节数组的大小为4K。我的第二个问题是:如果线程必须等待字节数组已满,我如何测量速度(在一秒钟的间隔内)? My answer should be: change the byte array size to a smaller value. 我的答案应该是:将字节数组的大小更改为较小的值。 But the file will get corrupted xD. 但是文件将损坏xD。

After trying to solve the problem by myself, I spent 2 days searching over the internet for a solution. 在尝试自己解决问题之后,我花了2天的时间在互联网上搜索解决方案。 And nothing. 没事了。

Please, can you guys answer my two questions? 拜托,你们能回答我的两个问题吗? Thanks =D 谢谢= D

Edit 编辑

Code for canDownload(): canDownload()的代码:

synchronized private boolean canDownload()
{
    return can_download;
}

My advice is to use a proven library such as Apache Commons IO instead of trying to roll your own code. 我的建议是使用成熟的库(例如Apache Commons IO),而不要尝试编写自己的代码。 For your particular problem, take a look at the copyURLToFile(URL, File) method. 对于您的特定问题,请看一下copyURLToFile(URL,File)方法。

I would: 我会:

  1. Change the RandomAccessFile to a FileOutputStream. 将RandomAccessFile更改为FileOutputStream。

  2. Get rid of canDownload() , whatever it's for, and set a read timeout on the connection instead. 摆脱canDownload() ,无论它做什么用,而改为在连接上设置读取超时。

  3. Simplify the copy loop to this: 将复制循环简化为此:

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

with all the exception handling outside this loop. 此循环外处理所有异常。

I think you will find the problem is that you closed the underlying InputStream while the RandomAccessFile still had data in its write buffers. 我认为您会发现问题是您关闭了底层InputStream,而RandomAccessFile的写缓冲区中仍然有数据。 This will be why you are occasionally missing the last few bytes of data. 这就是为什么您偶尔会丢失数据的最后几个字节的原因。

The race condition is between the JVM flushing the final write, and your call to i.close(). 竞争条件介于JVM刷新最终写操作和您对i.close()的调用之间。

Removing the i.close() should fix the problem; 删除i.close()应该可以解决问题; it isn't necessary as the raf.close() closes the underlying stream anyway, but this way you give the RAF a chance to flush any outstanding buffers before it does so. 不必这样做,因为raf.close()仍然会关闭基础流,但是通过这种方式,您可以为RAF提供一个在刷新之前清除所有未完成的缓冲区的机会。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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