Java 用于流的缓冲 base64 编码器

Java buffered base64 encoder for streams

我有很多 PDF 文件需要使用 base64 对其内容进行编码。我有一个 Akka 应用程序,它以流的形式获取文件并分发给许多工作人员以对这些文件和 returns 每个文件的字符串 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();
        }
    }

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

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

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

任何输入都非常有用。谢谢!

关于 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,但您实际上可以使用任何采用任意长度的字节数组和 returns 该字节数组的 ba​​se64 字符串的编码器。

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

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

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