【问题标题】:Downloading corrupted files with OkHttp使用 OkHttp 下载损坏的文件
【发布时间】:2017-05-27 09:14:34
【问题描述】:

我写的下载文件的方法总是产生损坏的文件。

public static String okDownloadToFileSync(final String link, final String fileName, final boolean temp, DownloadStatusManager statusManager, ErrorDisplayerInterface errorDisplayerInterface) {

    Request request = new Request.Builder()
            .url(link)
            .build();


    OkHttpClient client = Api.getInstance().getOkHttpClient();
    OutputStream output = null;
    InputStream input = null;

    try {

        Response response = client.newCall(request).execute();

        //Add the file length to the statusManager
        final int contentLength = Integer.parseInt(response.header("Content-Length"));
        if (statusManager != null) {
            statusManager.add(Hash.md5(link), contentLength);
        }

        //Get content type to know extension
        final String contentType = response.header("Content-Type");
        final String ext = contentTypeMap.get(contentType);

        Log.i(TAG, link + "\n --> contentType = " + contentType + "\n --> ext = " + ext);

        if (ext == null) {
            Log.e(TAG, "-----------\next is null, seems like there is a problem with that url : \n         " + link + "\n----------");
            return null;
        } else if (ext.equals("json")) {
            Log.e(TAG, "-----------\ndownloadable file seems to be a json, seems like there is a problem with that url : \n         " + link + "\n----------");
            return null;
        }

        //Check if file already exists
        if (!temp && fileName != null) {
            File test = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext);
            if (test.exists()) {
                Log.i(TAG, "File exists ! : " + test.getPath());
                test.delete();
                //return test.getAbsolutePath();
            }
        }

        // expect HTTP 200 OK, so we don't mistakenly save error report instead of the file
        if (!response.isSuccessful()) {
            errorDisplayerInterface.popWarn(null, "Error while downloading " + link, "connection.getResponseCode() != HttpURLConnection.HTTP_OK");
            return null;
        }

        input = response.body().byteStream();

        File file;
        if (temp) {
            file = File.createTempFile(UUID.randomUUID().toString(), ext, M360Application.getContext().getCacheDir());
        } else {
            file = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext);
        }


        output = new FileOutputStream(file);
        
        output.write(response.body().bytes());

//            byte data[] = new byte[4096];
//            long total = 0;
//            int count;
//            while ((count = input.read(data)) != -1) {
//                output.write(data, 0, count);
//                total++;
//
//                if (statusManager != null) {
//                    statusManager.update(Hash.md5(link), contentLength - total);
//                }
//           }

        return file.getAbsolutePath();
    } catch (IOException e) {
        e.printStackTrace();
        errorDisplayerInterface.popError(null, e);

    } finally {
        if (statusManager != null) {
            statusManager.finish(Hash.md5(link));
        }
        try {
            if (output != null)
                output.close();
            if (input != null)
                input.close();
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }

    }
    return null;
}

我通过 adb 访问这些文件,将它们传输到我的 sccard,在那里我看到它们似乎具有适当的大小,但根据例如 Linux file 命令没有类型。

您知道缺少什么以及如何解决吗?

谢谢。


编辑

更简单的代码版本(但是bug是一样的)

public static String okioDownloadToFileSync(final String link, final String fileName) throws IOException {

    Request request = new Request.Builder()
            .url(link)
            .build();


    OkHttpClient client = Api.getInstance().getOkHttpClient();
    Response response = client.newCall(request).execute();

    final int contentLength = Integer.parseInt(response.header("Content-Length"));

    //Get content type to know extension
    final String contentType = response.header("Content-Type");
    final String ext = contentTypeMap.get(contentType);

    // expect HTTP 200 OK, so we don't mistakenly save error report instead of the file
    if (!response.isSuccessful()) {
        return null;
    }

    File file = new File(M360Application.getContext().getFilesDir(), fileName + "." + ext);

    BufferedSink sink = Okio.buffer(Okio.sink(file));
    sink.writeAll(response.body().source());
    sink.close();

    Log.i(TAG, "file.length : " + file.length() + " | contentLength : " + contentLength);

    return file.getAbsolutePath();

}

日志:file.length : 2485394 | contentLength : 1399242


解决方案

问题是我从我的 API 单例中获取了 OkHttpClient,它被改造使用并且有多个拦截器。那些拦截器正在污染响应。

所以我OkHttpClient client = Api.getInstance().getOkHttpClient(); 变成了OkHttpClient client = new OkHttpClient.Builder().build();,现在一切正常!

非常感谢。我现在将方法分成更小的部分。

【问题讨论】:

  • 只是作为一个提示:从“干净的代码质量”的角度来看......你可以做很多事情来改进这个代码;从删除浪费(例如注释代码)开始,并更加关注“单层抽象”规则 - 你只是在那个糟糕的方法中做了太多事情。最后:阅读 try-with-resources。这样可以节省您最后的检查时间。
  • they seem to have ther proper size。似乎?你甚至不知道大小是否相等?到最后一个字节?
  • 您好,感谢您的反馈!注释代码向您展示我尝试了多种方式来提供文件。至于单一抽象规则,您建议移动什么?我觉得这个方法唯一能做的就是下载一个文件,我看不出我能提取什么。从来没有听说过 try-with-resources,我正在立即阅读。 @greenapps 在我写它的时候,我意识到我只检查了 KB 大小,而不是你所说的“到最后一个字节”,我目前正在编译检查这个事实
  • 我会尝试这种方法:stackoverflow.com/questions/25893030/…(80+ 的投票响应)
  • @greenapps 我应该早点检查:file.length:2485394 |内容长度:1399242

标签: java android download okhttp okhttp3


【解决方案1】:

而不是 output.write(response.body().bytes()); 试试这样的

byte[] buff = new byte[1024 * 4];

while (true) {
   int byteCount = input.read(buff);
   if (byteCount == -1) {
       break;
   }
   output.write(buff, 0, byteCount);
}

【讨论】:

  • 它看起来很像我之前尝试过的注释部分(就在 output.write(response.body().bytes()); 下方)。我没有取得更大的成功
  • 您的日志输出说明了什么?也许,您对内容类型和扩展有一些问题?
  • 扩展名没问题,文件大小不正确:Log.i(TAG, "file.length : " + file.length() + " | contentLength : " + contentLength); => file.length : 2485394 | contentLength : 1399242
  • 请试试这个建议并报告尺寸。
  • 从零到字节数救了我的命 xd
猜你喜欢
  • 2020-10-18
  • 2019-01-21
  • 2018-04-08
  • 1970-01-01
  • 2015-07-14
  • 2015-07-16
  • 2017-12-04
  • 2019-01-28
  • 1970-01-01
相关资源
最近更新 更多