Android 从 OKHTTP 下载二进制文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25893030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Download binary file from OKHTTP
提问by pratsJ
I am using OKHTTP client for networking in my android application.
我在我的 android 应用程序中使用 OKHTTP 客户端进行网络连接。
Thisexample shows how to upload binary file. I would like to know how to get inputstream of binary file downloading with OKHTTP client.
此示例显示如何上传二进制文件。我想知道如何使用 OKHTTP 客户端获取二进制文件下载的输入流。
Here is the listing of the example :
这是示例的清单:
public class InputStreamRequestBody extends RequestBody {
private InputStream inputStream;
private MediaType mediaType;
public static RequestBody create(final MediaType mediaType,
final InputStream inputStream) {
return new InputStreamRequestBody(inputStream, mediaType);
}
private InputStreamRequestBody(InputStream inputStream, MediaType mediaType) {
this.inputStream = inputStream;
this.mediaType = mediaType;
}
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
}
Current code for simple get request is:
简单获取请求的当前代码是:
OkHttpClient client = new OkHttpClient();
request = new Request.Builder().url("URL string here")
.addHeader("X-CSRFToken", csrftoken)
.addHeader("Content-Type", "application/json")
.build();
response = getClient().newCall(request).execute();
Now how do I convert the response to InputStream
. Something similar to response from Apache HTTP Client
like this for OkHttp
response:
现在我如何将响应转换为InputStream
. 类似于这样的响应,Apache HTTP Client
用于OkHttp
响应:
InputStream is = response.getEntity().getContent();
EDIT
编辑
Accepted answer from below. My modified code:
从下面接受答案。我修改后的代码:
request = new Request.Builder().url(urlString).build();
response = getClient().newCall(request).execute();
InputStream is = response.body().byteStream();
BufferedInputStream input = new BufferedInputStream(is);
OutputStream output = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
采纳答案by Nadir Belhaj
Getting ByteStream from OKHTTP
从 OKHTTP 获取 ByteStream
I've been digging around in the Documentation of OkHttpyou need to go this way
我一直在挖掘OkHttp的文档,你需要走这条路
use this method :
使用这种方法:
response.body().byteStream() wich will return an InputStream
response.body().byteStream() 将返回一个 InputStream
so you can simply use a BufferedReader or any other alternative
所以你可以简单地使用 BufferedReader 或任何其他替代品
OkHttpClient client = new OkHttpClient();
request = new Request.Builder().url("URL string here")
.addHeader("X-CSRFToken", csrftoken)
.addHeader("Content-Type", "application/json")
.build();
response = getClient().newCall(request).execute();
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
response.body().close();
回答by kiddouk
For what it's worth, I would recommend response.body().source()
from okio(since OkHttp is already supporting it natively) in order to enjoy an easier way to manipulate a large quantity of data that can come when downloading a file.
对于它的价值,我会response.body().source()
从okio推荐(因为 OkHttp 已经在本地支持它),以便享受一种更简单的方法来处理下载文件时可能出现的大量数据。
@Override
public void onResponse(Call call, Response response) throws IOException {
File downloadedFile = new File(context.getCacheDir(), filename);
BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile));
sink.writeAll(response.body().source());
sink.close();
}
A couple of advantages taken from the documentation in comparison with InputStream:
与 InputStream 相比,从文档中获得的几个优点:
This interface is functionally equivalent to InputStream. InputStream requires multiple layers when consumed data is heterogeneous: a DataInputStream for primitive values, a BufferedInputStream for buffering, and InputStreamReader for strings. This class uses BufferedSource for all of the above. Source avoids the impossible-to-implement available() method. Instead callers specify how many bytes they require.
Source omits the unsafe-to-compose mark and reset state that's tracked by InputStream; callers instead just buffer what they need.
When implementing a source, you need not worry about the single-byte read method that is awkward to implement efficiently and that returns one of 257 possible values.
And source has a stronger skip method: BufferedSource.skip(long) won't return prematurely.
该接口在功能上等同于 InputStream。当使用的数据是异构的时,InputStream 需要多个层:用于原始值的 DataInputStream、用于缓冲的 BufferedInputStream 和用于字符串的 InputStreamReader。此类将 BufferedSource 用于上述所有内容。Source 避免了不可能实现的 available() 方法。相反,调用者指定他们需要多少字节。
Source 省略了 InputStream 跟踪的 unsafe-to-compose 标记和重置状态;调用者只是缓冲他们需要的东西。
在实现源时,您不必担心难以有效实现并返回 257 个可能值之一的单字节读取方法。
而 source 有一个更强的跳过方法:BufferedSource.skip(long) 不会过早返回。
回答by e.shishkin
The best option to download (based on source code "okio")
下载的最佳选择(基于源代码“okio”)
private void download(@NonNull String url, @NonNull File destFile) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = okHttpClient.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
BufferedSink sink = Okio.buffer(Okio.sink(destFile));
Buffer sinkBuffer = sink.buffer();
long totalBytesRead = 0;
int bufferSize = 8 * 1024;
for (long bytesRead; (bytesRead = source.read(sinkBuffer, bufferSize)) != -1; ) {
sink.emit();
totalBytesRead += bytesRead;
int progress = (int) ((totalBytesRead * 100) / contentLength);
publishProgress(progress);
}
sink.flush();
sink.close();
source.close();
}
回答by Shubham Chaudhary
This is how I use Okhttp+ Okiolibraries while publishing download progress after every chunk download:
这是我如何使用Okhttp+奥基奥库,而每块下载后发布下载进度:
public static final int DOWNLOAD_CHUNK_SIZE = 2048; //Same as Okio Segment.SIZE
try {
Request request = new Request.Builder().url(uri.toString()).build();
Response response = client.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
File file = new File(getDownloadPathFrom(uri));
BufferedSink sink = Okio.buffer(Okio.sink(file));
long totalRead = 0;
long read = 0;
while ((read = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += read;
int progress = (int) ((totalRead * 100) / contentLength);
publishProgress(progress);
}
sink.writeAll(source);
sink.flush();
sink.close();
publishProgress(FileInfo.FULL);
} catch (IOException e) {
publishProgress(FileInfo.CODE_DOWNLOAD_ERROR);
Logger.reportException(e);
}
回答by Joolah
Better solution is to use OkHttpClient as:
更好的解决方案是使用 OkHttpClient 作为:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});