【发布时间】: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