Загрузите двоичный файл из OKHTTP

Я использую клиент OKHTTP для работы в сети в своем приложении для Android.

Этот пример показывает, как загрузить двоичный файл. Я хотел бы знать, как получить входной поток для загрузки двоичного файла с клиентом OKHTTP.

Вот список примера:

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

Текущий код для простого запроса на получение:

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. Что-то похожее на ответ от Apache HTTP Client как на ответ OkHttp:

InputStream is = response.getEntity().getContent();

ИЗМЕНИТЬ

Принятый ответ ниже. Модифицированный код:

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

Ответ 1

Получение ByteStream из OKHTTP

Я искал документацию OkHttp, вам нужно идти этим путем

используйте этот метод:

response.body(). byteStream(), который вернет InputStream

чтобы вы могли просто использовать 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();

Ответ 2

Для чего это стоит, я бы рекомендовал 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();
}

Несколько преимуществ, взятых из документации по сравнению с InputStream:

Этот интерфейс функционально эквивалентен InputStream. InputStream требует нескольких уровней, когда потребляемые данные являются гетерогенными: DataInputStream для примитивных значений, BufferedInputStream для буферизации и InputStreamReader для строк. Этот класс использует BufferedSource для всего вышеперечисленного. Источник избегает невозможного для реализации метода available(). Вместо этого вызывающие абоненты определяют, сколько байтов они требуют.

Источник исключает небезопасную составляющую метку и состояние reset, которое отслеживается с помощью InputStream; вместо этого просто буферизуют то, что им нужно.

При реализации источника вам не нужно беспокоиться об однобайтовом методе чтения, который неудобно эффективно внедрять и возвращает одно из 257 возможных значений.

И источник имеет более сильный метод пропуска: BufferedSource.skip(long) не будет возвращаться преждевременно.

Ответ 3

Вот как я использую библиотеки Okhttp + Okio при публикации результатов загрузки после каждой загрузки фрагмента:

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

Ответ 4

Лучшее решение - использовать 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);


                }
            });

Ответ 5

Лучший вариант для загрузки (на основе исходного кода "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();
}