簡體   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