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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:48:15  来源:igfitidea点击:

Download binary file from OKHTTP

androidinputstreambufferedinputstreamokhttp

提问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 Clientlike this for OkHttpresponse:

现在我如何将响应转换为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);


                }
            });