Java缓冲了用于流的base64编码器

时间:2016-08-22 14:59:21

标签: java encoding base64 bufferedinputstream

我需要大量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文件时阻止其他线程。

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

1 个答案:

答案 0 :(得分:6)

关于Base64的有趣事实:它需要三个字节,并将它们转换为四个字母。这意味着如果您读取可被3整除的块中的二进制数据,则可以将块提供给任何 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) );
    }
}

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

上面的示例是使用Java 8 Base64,但您可以使用任何采用任意长度的字节数组并返回该字节数组的base64字符串的编码器。

这意味着您可以根据需要使用缓冲区大小。

但是,如果希望输出与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")