20

ダウンロードマネージャーで一時停止/履歴書を実装しようとしています。ウェブを検索していくつかの記事を読み、それに応じてコードを変更しましたが、履歴書が正しく機能していないようです。何かアイデアはありますか?

                if (!downloadPath.exists()) 
                    downloadPath.mkdirs(); 

                if (outputFileCache.exists())
                {
                    downloadedSize = outputFileCache.length();
                    connection.setAllowUserInteraction(true);
                    connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");
                    connection.setConnectTimeout(14000);
                    connection.connect();
                    input = new BufferedInputStream(connection.getInputStream());
                    output = new FileOutputStream(outputFileCache, true);
                    input.skip(downloadedSize); //Skip downloaded size
                }
                else
                {
                    connection.setConnectTimeout(14000);
                    connection.connect();
                    input = new BufferedInputStream(url.openStream());
                    output = new FileOutputStream(outputFileCache);
                }

                fileLength = connection.getContentLength();                 


                byte data[] = new byte[1024];
                int count = 0;
                int __progress = 0;
                long total = downloadedSize;

                while ((count = input.read(data)) != -1 && !this.isInterrupted()) 
                {
                    total += count;
                    output.write(data, 0, count);
                    __progress = (int) (total * 100 / fileLength);

                }
                output.flush();
                output.close();
                input.close();
4

5 に答える 5

21

問題は修正されました。一時停止/再開を実装したい他のユーザー向けのコードは次のとおりです。

        if (outputFileCache.exists())
        {
            connection.setAllowUserInteraction(true);
            connection.setRequestProperty("Range", "bytes=" + outputFileCache.length() + "-");
        }

        connection.setConnectTimeout(14000);
        connection.setReadTimeout(20000);
        connection.connect();

        if (connection.getResponseCode() / 100 != 2)
            throw new Exception("Invalid response code!");
        else
        {
            String connectionField = connection.getHeaderField("content-range");

            if (connectionField != null)
            {
                String[] connectionRanges = connectionField.substring("bytes=".length()).split("-");
                downloadedSize = Long.valueOf(connectionRanges[0]);
            }

            if (connectionField == null && outputFileCache.exists())
                outputFileCache.delete();

            fileLength = connection.getContentLength() + downloadedSize;
            input = new BufferedInputStream(connection.getInputStream());
            output = new RandomAccessFile(outputFileCache, "rw");
            output.seek(downloadedSize);

            byte data[] = new byte[1024];
            int count = 0;
            int __progress = 0;

            while ((count = input.read(data, 0, 1024)) != -1 
                    && __progress != 100) 
            {
                downloadedSize += count;
                output.write(data, 0, count);
                __progress = (int) ((downloadedSize * 100) / fileLength);
            }

            output.close();
            input.close();
       }
于 2013-03-21T14:16:37.660 に答える
5

さらに情報がなければ何が悪いのかを判断することは不可能ですが、次の点に注意してください。

  1. HTTP / 1.1リクエストを行う必要があります(サンプルコードから見分けるのは難しいです)
  2. サーバーはHTTP/1.1をサポートする必要があります
  3. サーバーは、応答のAccept-Rangesヘッダーでサポート内容を通知します
  4. If-Rangeは、最終変更時刻ではなく、サーバーがリソースに対して提供したetagである必要があります

オリジンが実際に最初に範囲リクエストをサポートしていることをテストするための簡単なもので範囲リクエストをチェックする必要があります(curlやwgetなど)

于 2013-03-13T03:14:43.560 に答える
2

サーバーが応答するのに時間がかかる(タイムアウト制限を超える)か、すべてのサーバーが一時停止(再開)をサポートしているわけではないという事実もあります。また、天気予報ファイルがHttp、https、ftp、またはudpを介してダウンロードされることを熟考することもポイントです。

「一時停止」とは、ストリームの一部を読み取ってディスクに書き込むことを意味します。再開するときは、ヘッダーを使用して、ダウンロードする残りの内容を指定する必要があります

あなたは次のようなことを試みるかもしれません:

 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    if(ISSUE_DOWNLOAD_STATUS.intValue()==ECMConstant.ECM_DOWNLOADING){
         File file=new File(DESTINATION_PATH);
        if(file.exists()){
             downloaded = (int) file.length();
         connection.setRequestProperty("Range", "bytes="+(file.length())+"-");
    }
}else{
    connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
}
connection.setDoInput(true);
connection.setDoOutput(true);
progressBar.setMax(connection.getContentLength());
 in = new BufferedInputStream(connection.getInputStream());
 fos=(downloaded==0)? new FileOutputStream(DESTINATION_PATH): new FileOutputStream(DESTINATION_PATH,true);
 bout = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024];
int x = 0;
while ((x = in.read(data, 0, 1024)) >= 0) {
    bout.write(data, 0, x);
     downloaded += x;
     progressBar.setProgress(downloaded);
}

同期してみてください。

于 2013-03-21T10:15:14.883 に答える
1

この行からデバッグを開始します。

connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");

ソースコードからは何であるかを判断することはできないのでdownloadedSize、これ以上詳しく説明するのは難しいですが、形式はである必要がありますbytes=from-to

とにかく、よくある落とし穴を避けるために、ApacheHttpClientを使用することをお勧めします。これは、同様のトピックでApache HttpClientを使用している人からの質問であり、いくつかのサンプルコードが提供されています

于 2013-03-15T21:24:28.947 に答える
0

input.skip(downloadedSize)行を削除するだけでよいと思います。バイト範囲にHTTPヘッダーを設定すると、サーバーはそれらのバイトの送信をスキップします。

「aaaaabbbbbcccccddddd」で構成される20バイトの長さのファイルがあり、5バイトをダウンロードした後に転送が一時停止されたとします。次に、Rangeヘッダーにより、サーバーは「bbbbbcccccddddd」を送信します。このコンテンツをすべて読み取り、ファイルに追加する必要があります。skip()はありません。ただし、コード内のskip()呼び出しは、「bbbbb」をスキップし、「cccccddddd」をダウンロードしたままにします。ファイルの少なくとも50%をすでにダウンロードしている場合、skip()はすべての入力を使い果たし、何も起こりません。

また、stringy05の投稿にあるすべてのものが適用されます。サーバーがHTTP/1.1をサポートしていること、リソースでRangeヘッダーがサポートされていること(動的に生成されたコンテンツはサポートしていない可能性があります)、およびetagと変更日を使用してリソースが変更されていないことを確認する必要があります。

于 2013-03-21T01:55:12.800 に答える