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)をダウンロードすると、数バイトが再び失われました。「OK、4Kサイズでやってみよう」と言った。そして、バイト配列のサイズを4Kに変更しました。機能した!いいですが、4 GBのファイルをダウンロードすると、最後にバイトが失われました。「かっこいい、8Kサイズでやってみよう」と言った。次に、バイト配列のサイズを8Kに変更しました。働いた。

私の最初の質問は:なぜこれが起こるのですか?(バッファサイズを変更しても、ファイルは破損しません)。

理論的には、ファイルの破損の問題は、バイト配列のサイズをより大きな値に変更することで解決できます。しかし、別の問題があります。大きなバイト配列サイズでダウンロード速度(1秒間隔)を測定するにはどうすればよいですか?

例:ダウンロード速度が2KB/秒だとします。また、バイト配列のサイズは4 Kです。2番目の質問は、スレッドがバイト配列がいっぱいになるまで待機する必要がある場合、速度を(1秒間隔で)測定するにはどうすればよいですか?私の答えは次のようになります。バイト配列のサイズを小さい値に変更します。ただし、ファイルのxDは破損します。

自分で問題を解決しようとした後、2日間インターネットで解決策を探しました。そして何も。

どうか、私の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

問題は、RandomAccessFile の書き込みバッファーにまだデータがある間に、基になる InputStream を閉じたことだと思います。これが、データの最後の数バイトが時々失われる理由です。

競合状態は、JVM が最終的な書き込みをフラッシュしてから、i.close() への呼び出しの間にあります。

i.close() を削除すると問題が解決するはずです。いずれにしても raf.close() は基になるストリームを閉じるので必要ありませんが、このようにして、未処理のバッファをフラッシュする前に RAF にフラッシュする機会を与えます。

于 2012-06-14T03:18:57.060 に答える
1

私は...するだろう:

  1. RandomAccessFile を FileOutputStream に変更します。

  2. を取り除き、canDownload()代わりに接続に読み取りタイムアウトを設定します。

  3. コピー ループを次のように単純化します。

    while ((bytes_read = i.read(bytes)) > 0) { out.write(bytes, 0, bytes_read); 閉じる(); 閉める();

このループの外側ですべての例外処理を行います。

于 2012-06-14T01:56:28.740 に答える