【问题标题】:Okio/Okhttp download file using BufferedSink and decode Base64 without having whole file in memory multiple timesOkio/Okhttp 使用 BufferedSink 下载文件并解码 Base64,而无需将整个文件多次保存在内存中
【发布时间】:2018-06-12 12:39:24
【问题描述】:

atm 有点问题。对于我的“inapp”-更新即时通讯从我的网络空间下载新的 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();
                }
            }
        }

Buffer/Log 并不是必需的,只是在测试期间使用它来检查响应。

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

大多数替代方案都非常慢,例如之后重新打开文件,将字节读入内存,解码并将它们写回。

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

干杯

【问题讨论】:

    标签: java android okhttp okio


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我知道这个答案来得太晚了,而且 Yuri 的答案在技术上是正确的,但我认为最惯用的方法是利用 Okio 推广的组合模式创建一个从 Base64 解码的Source (或编码为 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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-08
        • 2014-10-22
        • 2016-02-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多