我有很多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
他们更快,但他们需要整个文件,对吗?另外,我不想在编码PDF文件时阻塞其他线程。
任何输入都很有帮助。谢谢你!
关于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.getMimeEncoder(64,new byte[] { 13, 10})
代替Base64.getEncoder()
。然后,当它编码时,您将从每个块中获得100个完整大小的行,除了最后一个。您可能需要在while循环中添加result.append("rn")
。
如果您的目标是读取许多文件并将它们全部转换为base64,那么有一种更短的方法可以做到这一点。
将打开文件以供读取、创建文件以供写入以及将数据从一个文件复制到另一个文件的负担留给Files.copy
。
并专注于通过java.util.Base64
编码器函数包装outputSteam将字节编码为base64: Base64.getEncoder().wrap(yourFileOutputStream)
.
因此,将/yourSubdirectory
中的文件转换为base64的整个过程可以像这样执行:
Files.walk(Paths.get("/yourSubdirectory"))
.filter(Files::isRegularFile)
.forEach(path -> {
try {
// Add ".b64" to the new base64 output file
File base64file = Paths.get(path.toString() + ".b64").toFile();
// Read the input file, convert to base 64 and write output file
Files.copy(path, Base64.getEncoder().wrap(new FileOutuptStream(base64file)));
} catch (IOException e) {
throw new RuntimeException(e);
}
});