在文件下载中实现暂停/恢复

时间:2013-03-11 21:45:52

标签: java android download downloading

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

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

5 个答案:

答案 0 :(得分:19)

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

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

答案 1 :(得分:5)

如果没有更多信息,不可能说出错误,但需要注意的事项:

  1. 您必须发出HTTP / 1.1请求(很难从示例代码中判断出来)
  2. 服务器必须支持HTTP / 1.1
  3. 服务器将通过响应中的Accept-Ranges标头告诉您它支持的内容
  4. If-Range应该是服务器为您提供资源的etag,而不是上次修改时间
  5. 你应该用简单的东西来检查你的范围请求,以便首先实际支持Range请求(如curl或wget)

答案 2 :(得分: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);
}

请尝试同步。

答案 3 :(得分:1)

我会从这一行开始调试:

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

从源代码开始,无法确定downloadedSize是什么,但很难进一步详细说明,但格式应为bytes=from-to

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

答案 4 :(得分:0)

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

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

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