Categories
android bufferedinputstream inputstream okhttp

Download binary file from OKHTTP

85

I am using OKHTTP client for networking in my android application.

This example shows how to upload binary file. I would like to know how to get inputstream of binary file downloading with OKHTTP client.

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

3

  • check my edited answer i’m waiting your feedback

    Sep 17, 2014 at 14:42

  • glad it worked for you man 😀

    Sep 17, 2014 at 14:49

  • as a side note, your InputStreamRequestBody is not going to work if there is an ioexception in the request and the HttpEngine is set to retry. See github.com/square/okhttp/blob/master/okhttp/src/main/java/com/… line 202, writeTo is called in a while loop. It will cause an error. (I stumbled upon this while uploading from a content:// inputstream)

    – njzk2

    Sep 17, 2014 at 15:01

38

Getting ByteStream from OKHTTP

I’ve been digging around in the Documentation of OkHttp you need to go this way

use this method :

response.body().byteStream() wich will return an InputStream

so you can simply use a BufferedReader or any other alternative

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

6

  • 3

    The example you mentioned from documentation will work for a request with simple data or webpage but for downloading a binary file, wouldn’t I need a bufferedinputstream? So that I can get the bytes in buffer and write them to Fileoutputstream to save in local storage?

    – pratsJ

    Sep 17, 2014 at 14:22

  • 1

    Edited with solution for binary

    Sep 17, 2014 at 14:24

  • 1

    OKHTTP response does not have getEntity() method like Apache HTTP Client. Made edits in the question

    – pratsJ

    Sep 17, 2014 at 14:32

  • Edited with ultimate answer 😉

    Sep 17, 2014 at 14:40

  • 14

    Do not use BufferedReader with binary data; it will be corrupted by the unnecessary byte-to-character decoding.

    Mar 15, 2015 at 20:34

38

Getting ByteStream from OKHTTP

I’ve been digging around in the Documentation of OkHttp you need to go this way

use this method :

response.body().byteStream() wich will return an InputStream

so you can simply use a BufferedReader or any other alternative

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

6

  • 3

    The example you mentioned from documentation will work for a request with simple data or webpage but for downloading a binary file, wouldn’t I need a bufferedinputstream? So that I can get the bytes in buffer and write them to Fileoutputstream to save in local storage?

    – pratsJ

    Sep 17, 2014 at 14:22

  • 1

    Edited with solution for binary

    Sep 17, 2014 at 14:24

  • 1

    OKHTTP response does not have getEntity() method like Apache HTTP Client. Made edits in the question

    – pratsJ

    Sep 17, 2014 at 14:32

  • Edited with ultimate answer 😉

    Sep 17, 2014 at 14:40

  • 14

    Do not use BufferedReader with binary data; it will be corrupted by the unnecessary byte-to-character decoding.

    Mar 15, 2015 at 20:34

12

The best option to download (based on source code “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();
}

3

  • write downloadFile method

    Apr 14, 2016 at 9:37

  • i cant get body.contentLength()…its always -1

    – H Raval

    Jul 11, 2016 at 12:46

  • 3

    Not positive but you’ll probably want to put the flush() and close() methods in a finally block to ensure that any exceptions will still flush and close them.

    Aug 21, 2019 at 19:25