通过互联网实现可下载文件的简历

14

当我不实现resume时,我的以下代码可正常下载文件,但在阅读更多解决方案并解决问题后,我知道我必须检查Last-Modified头并将其设置为连接,

但由于我得到错误,例如android Cannot set request property after connection is made或者我得到nullhttpURLConnection,所以我无法这样做,

我正在使用此reference

getHeaderField heaser返回:

{
  null=[HTTP/1.1 200 OK], 
  Cache-Control=[public], 
  Connection=[keep-alive], 
  Content-Length=[8037404], 
  Content-Md5=[VEqXHCc/Off7a6D0gRFpiQ==], 
  Content-Type=[image/jpeg], 
  Date=[Tue, 19 Jan 2016 07:24:36 GMT], 
  Etag=["544a971c273f39f7fb6ba0f481116989"], 
  Expires=[Sat, 29 Jul 2017 10:07:00 GMT], 
  Last-Modified=[Thu, 18 Dec 2014 08:44:34 GMT], 
  Server=[bws], 
  X-Android-Received-Millis=[1501063623576], 
  X-Android-Response-Source=[NETWORK 200], 
  X-Android-Selected-Protocol=[http/1.1], 
  X-Android-Sent-Millis=[1501063623532]
}

现在我该如何设置以便下载文件时有简历呢?

GitHub链接

public void run() {
    final URL         url;
    HttpURLConnection httpURLConnection = null;
    try {
        try {
            url = new URL(mUrl);
            String lastModified = httpURLConnection.getHeaderField("Last-Modified");
            if (!lastModified.isEmpty()) {
                httpURLConnection.setRequestProperty("If-Range", lastModified);
            }
            httpURLConnection = (HttpURLConnection) url.openConnection();

            if (mFile.exists()) {
                downloadedLength = mFile.length();
                Log.e("downloadedLength ", downloadedLength + "");
                httpURLConnection.setRequestProperty("Range", "bytes=" + downloadedLength + "-");
                fileOutputStream = new FileOutputStream(mFile, true);
            } else {
                fileOutputStream = new FileOutputStream(mFile);
            }
            httpURLConnection.setConnectTimeout(30000);
            httpURLConnection.setReadTimeout(30000);
            httpURLConnection.setRequestMethod("GET");
        } catch (IOException e) {
        }
        final int responseCode;
        final int total;
        try {
            responseCode = httpURLConnection.getResponseCode();
            total = httpURLConnection.getContentLength();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("ER UPDATE ", e.getMessage());
        }
        if (responseCode == 200) {
            try {
                inputStream = httpURLConnection.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("IOException ", e.getMessage());
            }
            final byte[] buffer   = new byte[4 * 1024];
            int          length   = -1;
            int          finished = 0;
            long         start    = System.currentTimeMillis();
            try {
                while ((length = inputStream.read(buffer)) != -1) {
                    if (!isDownloading()) {
                        throw new CanceledException("canceled");
                    }
                    fileOutputStream.write(buffer, 0, length);
                    finished += length;
                    if (System.currentTimeMillis() - start > 1000) {
                        onDownloadProgressing(finished, total);
                        start = System.currentTimeMillis();
                    }
                }
                onDownloadCompleted();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("ER UPDATE ", e.getMessage());
            }
        } else {
            Log.e("responseCode ", responseCode + "");
        }
    } catch (DownloadException e) {
        e.printStackTrace();
        Log.e("ER UPDATE ", e.getMessage());
    } catch (CanceledException e) {
        e.printStackTrace();
        Log.e("ER UPDATE ", e.getMessage());
    }
}

同时我得到的是206响应代码而不是200


1
为什么您不使用DownloadManager呢?它可以在后台下载,处理HTTP交互并在失败或连接更改和系统重新启动后重试下载,并已经实现了“恢复”功能。 - Andrii Omelchenko
@AndriiOmelchenko 对于这个实现,我找不到任何好的文档。 - DolDurma
DownloadManager是专门用于下载文件的工具,而且它的功能很好。你可以尝试使用这个示例来了解更多。 - Andrii Omelchenko
2个回答

6

1- 您之所以得到httpURLConnection的null值,是因为您在初始化之前尝试调用它,

即这一行代码

httpURLConnection = (HttpURLConnection) url.openConnection();

应该在这行之前:

String lastModified = httpURLConnection.getHeaderField("Last-Modified");

2- 在调用httpURLConnectionconnect()之前,您可以设置标头。因此,您需要设置任何您想要的内容,然后再连接。这样,您就不会收到错误提示:(android Cannot set request property after connection is made)

3- 206完全正确的,当使用Range时,这是您应该期望的,它表示部分内容成功,这也是您正在做的事情,即获取部分内容,如果您获取了全部内容,您将获得200

因此,总结一下,您的代码可能如下所示: 注意:请按照 //*** 查看所需更改。

编辑:所有问题都归结为这一行。

httpURLConnection.setRequestProperty("If-Range", lastModified);

当您设置该属性时,会抛出错误。
无论如何,当您查看此内容时,它是没有意义的。您正在询问最后修改时间是否等于您刚从连接获取的值!如果您想要这样做,您需要将lastModified存储在您的系统中,然后将其与从URLConn获取的值进行比较,并将其与文件长度(已下载)进行比较,然后进行完整下载或恢复下载。
以下是新代码:
public void run() {
    myLastModified = getLastModified(mFile.getName()); // get last stored value for this file (use file name or other key)
    int total =0;

    final URL         url;
    HttpURLConnection httpURLConnection = null;
    try {
        try {
            url = new URL(mUrl);

            httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setDoInput(true);

            httpURLConnection.setConnectTimeout(30000);
            httpURLConnection.setReadTimeout(30000);
            httpURLConnection.setRequestMethod("GET");

            //*** new way to handle download process
            total = httpURLConnection.getContentLength();
            if(mFile.exists()){
                if(mFile.length() == total){
                    //we are done, return.
                    return;
                }else{
                    //file was not completly donwloaded, now check lastModified:
                    long lastModified = httpURLConnection.getLastModified();//this gets the header "Last-Modified" and convert to long
                    if (lastModified == myLastModified) { //myLastModified should be retrived on each download and stored locally on ur system
                        downloadedLength = mFile.length();
                        Log.e("downloadedLength ", downloadedLength + "");
                        httpURLConnection = (HttpURLConnection) url.openConnection();
                        httpURLConnection.setDoInput(true);

                        httpURLConnection.setConnectTimeout(30000);
                        httpURLConnection.setReadTimeout(30000);
                        httpURLConnection.setRequestMethod("GET");

                        httpURLConnection.setRequestProperty("Range", "bytes=" + downloadedLength + "-"+ total); //add + total (TO)

                        //append mode
                        fileOutputStream = new FileOutputStream(mFile, true);
                    }else{
                        //file was modified after 1st uncompleted-download:
                        storeLastModified(lastModified, mFile.getName()); // use file name as key. can store in db or file ...

                        //don't set ant Range ... we want full download, with a fresh file
                        fileOutputStream = new FileOutputStream(mFile);
                    }//last mod IF

                }//Length check
            }else{
                //file not exist at all, create new file, set no Range we want full download...
                mFile.createNewFile();
                fileOutputStream = new FileOutputStream(mFile);
            }//file exists.

        } catch (IOException e) {
            e.printStackTrace();
        }
        final int responseCode;

        try {
            responseCode = httpURLConnection.getResponseCode();

        } catch (IOException e) {
            e.printStackTrace();
            Log.e("ER UPDATE ", e.getMessage());
        }

        //*****
        if (responseCode == 200 || responseCode == 206) {
            try {
                inputStream = httpURLConnection.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("IOException ", e.getMessage());
            }
            final byte[] buffer   = new byte[4 * 1024];
            int          length   = -1;
            int          finished = 0;
            long         start    = System.currentTimeMillis();
            try {
                while ((length = inputStream.read(buffer)) != -1) {
                    if (!isDownloading()) {
                        throw new CanceledException("canceled");
                    }
                    fileOutputStream.write(buffer, 0, length);
                    finished += length;
                    if (System.currentTimeMillis() - start > 1000) {
                        onDownloadProgressing(finished, total);
                        start = System.currentTimeMillis();
                    }
                }
                onDownloadCompleted();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("ER UPDATE ", e.getMessage());
            }
        } else {
            Log.e("responseCode ", responseCode + "");
        }
    } catch (DownloadException e) {
        e.printStackTrace();
        Log.e("ER UPDATE ", e.getMessage());
    } catch (CanceledException e) {
        e.printStackTrace();
        Log.e("ER UPDATE ", e.getMessage());
    }
}

@Mahdi.Pishguy,是的,你说得对,我之前没有仔细看你的代码(逻辑上),现在我看了一下,发现“if-range”并没有太多意义,所以请查看我的新代码,看看 EDIT - Yazan
我在这行代码 httpURLConnection.setDoInput(true); 中遇到了错误 java.lang.IllegalStateException: Already connected。我已经注释掉了 httpURLConnection.connect();,并将更改上传到了 Git 存储库。 - DolDurma
@Mahdi.Pishguy请删除它,我为您留下了一条评论,如果它引起问题,请将其删除。 - Yazan
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/150788/discussion-between-mahdi-pishguy-and-yazan。 - DolDurma
嗨,伙计,你能帮我看一下这个话题吗?谢谢。 - DolDurma

1
请看this的回答,涉及POMATu。 无论如何,如果您通过HTTP协议下载文件,可以使用DownloadManager - 一个系统服务(从 API 级别 9 开始)用于在后台进行长时间运行的下载。它处理HTTP连接、连接状态变化、重新启动,并确保每个下载成功完成。它已经支持恢复和进度通知。请注意保留HTML标签。

您可以找到很多类似 this 的教程或者 that 的例子,以及在 stackoverflow 上通过 标签找到很多解决方案。


也许你是对的,但这并不是我的问题的答案。 - DolDurma
这取决于您 :) 是的 - 这不是答案:只是关于您问题的其他方法的通知。也许对某些人有用。 - Andrii Omelchenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接