12/08/2018, 13:54

Resume download file

Khi chúng ta thực hiện download một file từ server, vì nhiều lý do mà có thể bị mất kết nối giữa chừng và việc download sẽ bị bỏ dở. Khi đó có 2 lựa chọn là download lại từ đầu hoặc resume download. Tất nhiên chúng ta sẽ mong muốn có hỗ trợ resume download hơn. Việc resume download ở đây cần có cả ...

Khi chúng ta thực hiện download một file từ server, vì nhiều lý do mà có thể bị mất kết nối giữa chừng và việc download sẽ bị bỏ dở. Khi đó có 2 lựa chọn là download lại từ đầu hoặc resume download. Tất nhiên chúng ta sẽ mong muốn có hỗ trợ resume download hơn. Việc resume download ở đây cần có cả sự hỗ trợ từ phía server.

Đầu tiên, chúng ta lấy link download và kiểm tra server có hỗ trợ không bằng postman, ví dụ với link http://www.mediafire.com/download/9eja28r5n84g8hb/Pokemon_Go_0.29.3_%23FAMILIAQSE.apk

sau khi dùng postman với HEAD request

Screenshot from 2016-09-26 14:08:55.png

ở đây mình thấy có trường Accept-Ranges, nhiều khả năng là sẽ hỗ trợ, để kiểm tra tiếp theo, thêm vào phần header trường Range và chú ý ở phần Content-Length trả về

Screenshot from 2016-09-26 14:12:09.png

ở đây mình truyền lên Range để lấy data từ byte thứ 100000 đến hết, thì nhìn ở phần Content-Length thấy dung lượng sẽ nhỏ hơn ở hình phía trên 100000, có thêm Content-Range để chỉ những byte sẽ được lấy. Như vậy là server có hỗ trợ Resume download

Bây giờ đến phần client: Ở đây mình dùng HttpUrlConnection luôn

private int downloadFile(String url, String filepath) {
        double processedSize = 0;
        FileOutputStream fos;
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("GET");
            File file = new File(filepath);
            if (file.exists()) {
                processedSize = file.length();
                connection.setRequestProperty("Range", "bytes=" + file.length() + "-");
            }
            connection.connect();
            int responceCode = connection.getResponseCode();
            if (responceCode != 200 && responceCode != 206) {
                if (responceCode == 404) {
                    return RESULT_NOTFOUND;
                }
                return RESULT_SERVERERROR;
            }
            double totalSize = connection.getContentLength();
            if (totalSize == 0) {        //Cần chú ý chỗ này (giải thích bên dưới)
                //if (responceCode == 206)
                //    return RESULT_OK;
                return RESULT_ERROR;
            }
            if (totalSize < 0) {
                return RESULT_ERROR;
            }
            if (file.exists()) {
                totalSize = totalSize + file.length();
                publishProgressDownload(file.length(), totalSize);
            } else
                publishProgressDownload(processedSize, totalSize);
            if (file.exists())
                fos = new FileOutputStream(filepath, true);
            else
                fos = new FileOutputStream(filepath);
            InputStream is = connection.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
                processedSize += len;
                publishProgressDownload(processedSize, totalSize);
            }
            fos.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
            return RESULT_ERROR;
        }
        return RESULT_OK;
    }

Ở đây có 2 chỗ cần chú ý nữa là

fos = new FileOutputStream(filepath, true);

Nếu đã down mà chưa thành công, tức là còn file ở máy, thì sẽ ghi tiếp vào, khi đó sẽ có true vào trong param để báo là sẽ ghi tiếp vào file đó.

Còn ở chỗ

if (totalSize == 0) {

thì khi đã download xong hoàn toàn, tuy nhiên lại request lên thì Range truyền lên sẽ = file.length(), tùy server sẽ trả về khác nhau, ở mediafire thì mình thấy nó trả về content-length là full length, trong khi có server thì trả về 0. Trường hợp đã download hoàn toàn rồi mà vẫn cần request lên thì khá ít. Nếu trường hợp trả về = 0 thì có thể xử lý như trong đoạn code được comment để báo là đã download hết rồi.

Cảm ơn mọi người đã đọc bài, có gì góp ý mọi người comment phía dưới nhé

0