Pobierz plik binarny z OKHTTP

Używam klienta OKHTTP dla sieci w mojej aplikacji na Androida.

Ten przykład pokazuje, jak przesłać plik binarny. Chciałbym się dowiedzieć, jak wprowadzić strumień plików binarnych do pobrania za pomocą klienta OKHTTP.

Oto lista przykładu:

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

Bieżący kod dla prostego żądania get to:

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

Teraz Jak przekonwertować odpowiedź na InputStream. Coś podobnego do odpowiedzi z Apache HTTP Client Jak to dla OkHttp odpowiedź:

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

Edytuj

Akceptuję odpowiedź od dołu. Mój zmodyfikowany kod:

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();
Author: Community, 2014-09-17

5 answers

Pobieranie ByteStream z OKHTTP

Grzebałem w dokumentacji OkHttp musisz iść tą drogą

Użyj tej metody:

ODPOWIEDŹ.body ().byteStream (), który zwróci strumień wejściowy

możesz więc po prostu użyć Bufferedreadera lub innej alternatywy

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();
 27
Author: Nadir Belhaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-07 04:28:41

Jeśli to coś warte, polecam response.body().source() z okio (ponieważ OkHttp obsługuje go już natywnie), aby cieszyć się łatwiejszym sposobem manipulowania dużą ilością danych, które mogą pojawić się podczas pobierania pliku.

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

Kilka zalet zaczerpniętych z Dokumentacji w porównaniu z InputStream:

Ten interfejs jest funkcjonalnie równoważny do InputStream. InputStream wymaga wielu warstw, gdy zużyte dane są niejednorodne: a DataInputStream dla wartości pierwotnych, Buforedinputstream dla buforowania i InputStreamReader dla ciągów znaków. Ta klasa używa BufferedSource dla wszystkich powyższych. Source unika niemożliwej do implementacji metody available (). Zamiast tego wywołujący określają, ile bajtów wymagają.

Source pomija znacznik unsafe-to-compose i stan resetowania śledzony przez strumień wejściowy; wywołujący zamiast tego buforują to, czego potrzebują.

Implementując źródło, nie musisz się martwić o jednobajtowa Metoda odczytu, która jest niewygodna do efektywnej implementacji i zwraca jedną z 257 możliwych wartości.

I source ma mocniejszą metodę pomijania: BufferedSource.skip (long) nie powróci przedwcześnie.

 138
Author: kiddouk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-01 05:40:33

Najlepsza opcja do pobrania (na podstawie kodu źródłowego "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();
}
 8
Author: e.shishkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-14 20:50:10

Tak używam Okhttp + Okio biblioteki podczas publikowania postępu pobierania po każdym pobraniu fragmentu:

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);
}
 6
Author: Shubham Chaudhary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-06 11:51:02

Lepszym rozwiązaniem jest użycie OkHttpClient jako:

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
Author: Joolah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-17 10:49:31