【问题标题】:Implement pause/resume in file downloading在文件下载中实现暂停/恢复
【发布时间】:2013-03-11 21:45:52
【问题描述】:

我正在尝试在我的下载管理器中实现暂停/恢复,我在网上搜索并阅读了几篇文章并根据它们更改了我的代码,但恢复似乎无法正常工作,有什么想法吗?

                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();

【问题讨论】:

  • 究竟是什么不工作??
  • @BrianPlummer 当我暂停并继续下载时,下载从头开始,并在到达我暂停的最后状态时锁定。
  • @BrianPlummer 我认为这条线 (int) (total * 100 / fileLength) 返回错误的进度!
  • @DKN 为什么你使用input.skip(downloadedSize);,这不是从服务器端完成的吗?
  • input.skip(downloadedSize); 的结果真的等于downloadedSize 吗?

标签: java android download


【解决方案1】:

好的问题已解决,这是我为其他想要实现暂停/恢复的用户提供的代码:

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

【讨论】:

  • 为什么设置connection.setAllowUserInteraction(true);?文档说:'设置允许用户交互。安卓未使用。为什么需要它?
  • 真正的问题是什么?
  • @NullPointer,你如何初始化outputFileCache?
【解决方案2】:

如果没有更多信息,就无法判断出了什么问题,但是需要注意的事项:

  1. 您必须发出 HTTP/1.1 请求(从您的示例代码中很难看出)
  2. 服务器必须支持 HTTP/1.1
  3. 服务器将通过响应中的 Accept-Ranges 标头告诉您它支持什么
  4. If-Range 应该是服务器为资源提供的 etag,而不是上次修改时间

你应该用一些简单的东西来检查你的范围请求,以测试原点实际上首先支持范围请求(如 curl 或 wget )

【讨论】:

    【解决方案3】:

    可能是您的服务器响应时间过长(超过超时限制),或者这也是并非所有服务器都支持暂停 - 恢复的事实。 还有一点需要思考的是,文件是通过 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);
    }
    

    请尝试同步内容。

    【讨论】:

    • 不要使用connection.setDoInput(true);和connection.setDoOutput(true);,会导致另一个问题。
    • 如果要发送(输出)请求正文,例如使用 POST 或 PUT 请求,则需要将其设置为 true。使用 GET,您通常不会发送正文,因此您不需要它。同样,要接收带有传入响应的正文,您需要将输入设置为 true。发送请求正文本身是通过连接的输出流完成的:conn.getOutputStream().write(someBytes);
    • 我不认为'__progress = (int) (total * 100 / fileLength);'做错了什么
    【解决方案4】:

    我将从这一行开始调试:

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

    从源代码中无法确定downloadedSize是什么,很难进一步阐述,但格式应该是bytes=from-to。

    无论如何,我建议您使用Apache HttpClient 来避免常见的陷阱。 Here 是一个使用 Apache HttpClient 的人提出的一个类似主题的问题,并提供了一些示例代码。

    【讨论】:

      【解决方案5】:

      我认为您只需要删除 input.skip(downloadedSize) 行。为字节范围设置 HTTP 标头意味着 服务器 将跳过 发送 这些字节。

      假设您有一个包含“aaaaabbbbbcccccddddd”的 20 字节长的文件,并假设在下载 5 字节后传输暂停。然后 Range 标头将导致服务器发送“bbbbbcccccddddd”,您应该阅读此内容的所有并将其附加到文件中——不要跳过()。但是代码中的 skip() 调用将跳过“bbbbb”,留下“cccccddddd”要下载。如果您已经下载了至少 50% 的文件,那么 skip() 将耗尽所有输入并且不会发生任何事情。

      此外,stringy05 帖子中的所有内容都适用。您应该确保服务器支持 HTTP/1.1,确保资源支持 Range 标头(动态生成的内容可能不支持),并确保资源没有使用 etag 和修改日期进行修改。

      【讨论】:

      • 试过但没有任何改变。
      猜你喜欢
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 2021-07-07
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多