[android] OKHTTP에서 바이너리 파일 다운로드

내 안드로이드 응용 프로그램에서 네트워킹을 위해 OKHTTP 클라이언트를 사용하고 있습니다.

예제는 바이너리 파일을 업로드하는 방법을 보여줍니다. OKHTTP 클라이언트로 다운로드하는 바이너리 파일의 inputstream을 얻는 방법을 알고 싶습니다.

다음은 예제 목록입니다.

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

간단한 get 요청의 현재 코드는 다음과 같습니다.

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



답변

OKHTTP에서 ByteStream 가져 오기

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


답변

무엇의 가치를 위해, 나는 추천 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 () 메서드를 피합니다. 대신 호출자는 필요한 바이트 수를 지정합니다.

Source는 InputStream에 의해 추적되는 unsafe-to-compose 표시 및 재설정 상태를 생략합니다. 대신 호출자는 필요한 것을 버퍼링합니다.

소스를 구현할 때 효율적으로 구현하기 어색하고 257 개의 가능한 값 중 하나를 반환하는 단일 바이트 읽기 메서드에 대해 걱정할 필요가 없습니다.

소스에는 더 강력한 스킵 메소드가 있습니다. BufferedSource.skip (long)은 너무 일찍 반환되지 않습니다.


답변

가장 좋은 다운로드 옵션 (소스 코드 “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();
}


답변

다음은 청크 다운로드 후 다운로드 진행률을 게시하는 동안 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);
}


답변

더 나은 솔루션은 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);


                }
            });


답변

kiddouk 답변을 기반으로 한 Kotlin 버전

 val request = Request.Builder().url(url).build()
 val response = OkHttpClient().newCall(request).execute()
 val downloadedFile = File(cacheDir, filename)
 val sink: BufferedSink = downloadedFile.sink().buffer()
 sink.writeAll(response.body!!.source())
 sink.close()


답변