Okio / Okhttp使用BufferedSink下载文件并解码Base64,而不需要多次在内存中存储整个文件

时间:2018-01-02 20:08:56

标签: java android okhttp okio

atm有点问题。对于我的" inapp" -update我从我的网站空间下载新的base64编码的.apk。我的功能很少,这是没有解码的代码。

            public void onResponse(Call call, Response response) throws IOException {
            if(response.isSuccessful()){
                ResponseBody body = response.body();
                BufferedSource source = body.source();
                source.request(Long.MAX_VALUE);
                Buffer buffer = source.buffer();

                String rString = buffer.clone().readString(Charset.forName("UTF-8"));
                Log.i("Test: ", AppUtils.decodeBase64(rString));

                if(rString.equals("xxx")){
                    EventBus.getDefault().post(new KeyNotValid());
                    dispatcher.cancelAll();
                }else{
                    EventBus.getDefault().post(new SaveKey(apikey));
                    BufferedSink sink = Okio.buffer(Okio.sink(myFile));
                    sink.writeAll(source);
                    sink.flush();
                    sink.close();
                }
            }
        }

缓冲区/日志不是必需的,只是用它来检查测试期间的响应。

在将字节写入接收器之前,我将如何解码字节? 我尝试过这样做。 ByteString,但我找不到将解码后的String写回BufferedSource的方法。

大多数替代方案都很慢,就像之后重新打开文件,将字节读入内存,解码并写回来一样。

非常感谢您对此有任何帮助

欢呼声

2 个答案:

答案 0 :(得分:0)

您已经可以通过ResponseBody.byteStream将响应作为InputStream使用。您可以使用https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64InputStream.html修饰此流,并使用它来读取字节流并将其写入接收器中的文件接收器。

答案 1 :(得分:0)

我知道这个答案很晚才到,Yuri的答案在技术上是正确的,但我认为最常用的方法是利用Okio推出的组合模式创建一个Source来解码Base64(或编码为Base64的Sink,如果您需要的话)。

这是一个概念证明(我确信它可以改进):

public class Base64Source implements Source {

    private Source delegate;
    private Base64.Decoder decoder; // Using Java 8 API, but it can be any library

    public Base64Source(Source delegate) {
        this(delegate, Base64.getDecoder());
    }

    public Base64Source(Source delegate, Base64.Decoder decoder) {
        this.delegate = delegate;
        this.decoder = decoder;
    }

    @Override
    public long read(Buffer sink, long byteCount) throws IOException {
        Buffer buffer = new Buffer();
        long actualRead = this.delegate.read(buffer, byteCount);
        if (actualRead == -1) {
            return -1;
        }

        byte[] encoded = buffer.readByteArray(actualRead);
        byte[] decoded = decoder.decode(encoded);
        sink.write(decoded);

        return decoded.length;
    }

    @Override
    public Timeout timeout() {
        return this.delegate.timeout();
    }

    @Override
    public void close() throws IOException {
        this.delegate.close();
    }
}

以下是它的使用方法

BufferedSource source = Okio.buffer(new Base64Source(originalSource));
BufferedSink sink = ... // create sink
sink.writeAll(source);

// Don't forget to close the source/sink to flush and free resources
sink.close();
source.close();