使用 OkHttp 下载损坏的文件 [英] Downloading corrupted files with OkHttp

查看:116
本文介绍了使用 OkHttp 下载损坏的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

public static String okDownloadToFileSync(final String link, final String fileName, final boolean temp, DownloadStatusManager statusManager, ErrorDisplayerInterface errorDisplayerInterface) {请求请求 = new Request.Builder().url(链接).建造();OkHttpClient 客户端 = Api.getInstance().getOkHttpClient();OutputStream 输出 = 空;InputStream 输入 = 空;尝试 {响应 response = client.newCall(request).execute();//将文件长度添加到statusManagerfinal int contentLength = Integer.parseInt(response.header(Content-Length"));如果(状态管理器!= null){statusManager.add(Hash.md5(link), contentLength);}//获取内容类型以了解扩展名final String contentType = response.header(Content-Type");最终字符串 ext = contentTypeMap.get(contentType);Log.i(TAG, link + "\n --> contentType = "+ contentType + "\n --> ext = "+ ext);如果(分机 == 空){Log.e(TAG, "-----------\next is null, 好像那个 url 有问题:\n " + link + "\n----------");返回空;} else if (ext.equals("json")) {Log.e(TAG, "-----------\ndownloadable file 好像是一个json,好像那个url有问题:\n " + link + "\n----------");返回空;}//检查文件是否已经存在if (!temp && fileName != null) {File test = new File(M360Application.getContext().getFilesDir(), fileName + ." + ext);如果(测试存在()){Log.i(TAG, "文件存在!:" + test.getPath());测试删除();//返回 test.getAbsolutePath();}}//期望 HTTP 200 OK,所以我们不会错误地保存错误报告而不是文件如果 (!response.isSuccessful()) {errorDisplayerInterface.popWarn(null, 下载时出错" + 链接, connection.getResponseCode() != HttpURLConnection.HTTP_OK");返回空;}输入 = response.body().byteStream();档案档案;如果(温度){file = File.createTempFile(UUID.randomUUID().toString(), ext, M360Application.getContext().getCacheDir());} 别的 {file = new File(M360Application.getContext().getFilesDir(), fileName + ." + ext);}输出 = 新的 FileOutputStream(file);output.write(response.body().bytes());//字节数据[] = 新字节[4096];//总长 = 0;//整数计数;//while ((count = input.read(data)) != -1) {//output.write(data, 0, count);//总++;////if (statusManager != null) {//statusManager.update(Hash.md5(link), contentLength - total);//}//}返回 file.getAbsolutePath();} catch (IOException e) {e.printStackTrace();errorDisplayerInterface.popError(null, e);} 最后 {如果(状态管理器!= null){statusManager.finish(Hash.md5(link));}尝试 {如果(输出!= null)输出关闭();如果(输入!= null)input.close();} catch(忽略IOException){忽略.printStackTrace();}}返回空;}

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

您是否知道缺少什么以及如何修复它?

谢谢.


编辑

代码的简单版本(但错误是相同的)

public static String okioDownloadToFileSync(final String link, final String fileName) 抛出 IOException {请求请求 = new Request.Builder().url(链接).建造();OkHttpClient 客户端 = Api.getInstance().getOkHttpClient();响应 response = client.newCall(request).execute();final int contentLength = Integer.parseInt(response.header(Content-Length"));//获取内容类型以了解扩展名final String contentType = response.header(Content-Type");最终字符串 ext = contentTypeMap.get(contentType);//期望 HTTP 200 OK,所以我们不会错误地保存错误报告而不是文件如果 (!response.isSuccessful()) {返回空;}File file = new File(M360Application.getContext().getFilesDir(), fileName + ." + ext);BufferedSink sink = Okio.buffer(Okio.sink(file));sink.writeAll(response.body().source());接收器关闭();Log.i(TAG, "file.length : " + file.length() + " | contentLength : " + contentLength);返回 file.getAbsolutePath();}

<块引用>

日志:file.length:2485394 |内容长度:1399242


解决方案

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

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

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

解决方案

代替output.write(response.body().bytes());尝试这样的事情

byte[] buff = new byte[1024 * 4];而(真){int byteCount = input.read(buff);如果(字节数 == -1){休息;}output.write(buff, 0, byteCount);}

The method I wrote to download files always produce corrupted files.

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

I access these file via adb, transfer them to my sccard, and there I see that they seem to have the proper size, but has no type according to for instance Linux file command.

Would you know what is missing and how to fix it?

Thank you.


Edit

Simpler version of the code ( but the bug is the same )

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

}

The log : file.length : 2485394 | contentLength : 1399242


Solution

The problem was that I was getting the OkHttpClient from my API singleton, which was used by retrofit and had multiples interceptors. Those interceptors were polluting the response.

So I OkHttpClient client = Api.getInstance().getOkHttpClient(); became OkHttpClient client = new OkHttpClient.Builder().build(); and everything is now ok !

Thanks a lot. I'm dividing the method into smaller pieces right now.

解决方案

Instead of output.write(response.body().bytes()); try something like this

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

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

这篇关于使用 OkHttp 下载损坏的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆