【问题标题】:Java buffered base64 encoder for streams用于流的 Java 缓冲 base64 编码器
【发布时间】:2016-08-22 14:59:20
【问题描述】:

我有很多 PDF 文件,我需要使用 base64 对其内容进行编码。我有一个 Akka 应用程序,它将文件作为流获取并分发给许多工作人员以对这些文件进行编码并为每个文件返回字符串 base64。我有一个基本的编码解决方案:

    org.apache.commons.codec.binary.Base64InputStream;
    ...
    Base64InputStream b64IStream = null;
    InputStreamReader reader = null;
    BufferedReader br = null;
    StringBuilder sb = new StringBuilder();
    try {
        b64IStream = new Base64InputStream(input, true);
        reader = new InputStreamReader(b64IStream);
        br = new BufferedReader(reader);
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
    } finally {
        if (b64IStream != null) {
            b64IStream.close();
        }
        if (reader != null) {
            reader.close();
        }
        if (br != null) {
            br.close();
        }
    }

它有效,但我想知道使用缓冲区对文件进行编码的最佳方式是什么,以及是否有更快的替代方案。

我测试了一些其他方法,例如:

  • Base64.getEncoder
  • sun.misc.BASE64Encoder
  • Base64.encodeBase64
  • javax.xml.bind.DatatypeConverter.printBase64
  • com.google.guava.BaseEncoding.base64

他们更快,但他们需要整个文件,对吗?另外,我不想在编码 1 个 PDF 文件时阻塞其他线程。

任何输入都非常有帮助。谢谢!

【问题讨论】:

  • 你是什么意思“有缓冲区”。输入将是什么,您期望输出是什么?流?一个频道?一个字符串?
  • 输入为InputStream,输出为base64字符串内容。缓冲区将是 BufferedReader。

标签: java encoding base64 bufferedinputstream


【解决方案1】:

关于 Base64 的有趣事实:它需要三个字节,并将它们转换为四个字母。这意味着如果您读取可被三整除的块中的二进制数据,您可以将这些块提供给 any Base64 编码器,它会以与将整个文件提供给它的方式相同的方式对其进行编码.

现在,如果您希望输出流只是一长行 Base64 数据 - 这是完全合法的 - 那么您需要做的就是:

private static final int BUFFER_SIZE = 3 * 1024;

try ( BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE); ) {
    Base64.Encoder encoder = Base64.getEncoder();
    StringBuilder result = new StringBuilder();
    byte[] chunk = new byte[BUFFER_SIZE];
    int len = 0;
    while ( (len = in.read(chunk)) == BUFFER_SIZE ) {
         result.append( encoder.encodeToString(chunk) );
    }
    if ( len > 0 ) {
         chunk = Arrays.copyOf(chunk,len);
         result.append( encoder.encodeToString(chunk) );
    }
}

这意味着只有最后一个块的长度不能被三整除,因此将包含填充字符。

上面的例子是使用 Java 8 Base64,但你真的可以使用任何编码器,它接受任意长度的字节数组并返回该字节数组的 ba​​se64 字符串。

这意味着您可以随意调整缓冲区大小。

但是,如果您希望输出与 MIME 兼容,则需要将输出分成几行。在这种情况下,我会将上面示例中的块大小设置为当乘以 4/3 时,可以得到整数的行数。例如,如果您希望每行有 64 个字符,则每行编码 64 / 4 * 3,即 48 个字节。如果你编码 48 个字节,你会得到一行。如果你编码 480 字节,你会得到 10 行。

所以将上面的 BUFFER_SIZE 修改为类似 4800 的值。而不是 Base64.getEncoder() 使用 Base64.getMimeEncoder(64,new byte[] { 13, 10})。然后,当它编码时,除了最后一个块之外,您将从每个块中获得 100 条全尺寸行。您可能需要在 while 循环中添加 result.append("\r\n")

【讨论】:

  • 非常感谢!!我只需要切换编码器,因为我使用的是 java 6。在此更改之前,编码需要大约 900 毫秒,现在同一文件的平均需要 103 毫秒。
  • 此解决方案似乎无法与来自 url 的 InputStreams 一起正常工作,除非我将所有内容缓冲到一个 byte[] 中,然后输入一个新的 ByteArrayInputStream。
  • 修复了可变长度流。 gist.github.com/laxika/b9475e042973cf69ae4f2b3524575abb 但是,我不确定它是否适用于所有 InputStream 实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 2012-10-08
  • 2017-12-08
  • 2013-08-25
  • 1970-01-01
  • 2019-06-15
相关资源
最近更新 更多