Java将PDF转换为Base64

2025/04/13

1. 概述

在这个简短的教程中,我们将了解如何使用Java 8和Apache Commons Codec对PDF文件进行Base64编码和解码

首先,让我们快速了解一下Base64的基础知识。

2. Base64基础知识

在线上发送数据时,我们需要以二进制格式发送,但如果我们只发送0和1,不同的传输层协议可能会对它们进行不同的解释,导致数据在传输过程中损坏。

因此,为了在传输二进制数据时具有可移植性和通用标准,Base64应运而生

由于发送方和接收方都理解并同意使用该标准,因此我们的数据丢失或被误解的可能性大大降低。

现在让我们看看将其应用于PDF的几种方法。

3. 使用Java 8进行转换

从Java 8开始,引入了一个实用程序java.util.Base64,它为Base64编码方案提供编码器和解码器。它支持RFC 4648RFC 2045中指定的Basic、URL安全以及MIME类型。

3.1 编码

要将PDF转换为Base64,我们首先需要以字节为单位获取它,然后通过java.util.Base64.Encoder的编码方法传递它

byte[] inFileBytes = Files.readAllBytes(Paths.get(IN_FILE)); 
byte[] encoded = java.util.Base64.getEncoder().encode(inFileBytes);

这里,IN_FILE是我们输入PDF的路径。

3.2 流编码

对于较大的文件或内存有限的系统,使用流执行编码比读取内存中的所有数据效率更高,让我们看看如何实现这一点:

try (OutputStream os = java.util.Base64.getEncoder().wrap(new FileOutputStream(OUT_FILE)); FileInputStream fis = new FileInputStream(IN_FILE)) {
    byte[] bytes = new byte[1024];
    int read;
    while ((read = fis.read(bytes)) > -1) {
        os.write(bytes, 0, read);
    }
}

这里,IN_FILE是输入PDF的路径,OUT_FILE是包含Base64编码文档的文件路径。我们不是将整个PDF读入内存,然后在内存中对整个文档进行编码,而是一次读取最多1KB的数据,并将该数据通过编码器传递到OutputStream中。

3.3 解码

在接收端,我们得到编码的文件。

因此我们现在需要对其进行解码以取回原始字节,并将它们写入FileOutputStream以获取解码后的PDF

byte[] decoded = java.util.Base64.getDecoder().decode(encoded);

FileOutputStream fos = new FileOutputStream(OUT_FILE);
fos.write(decoded);
fos.flush();
fos.close();

这里,OUT_FILE是我们要创建的PDF的路径。

4. 使用Apache Commons进行转换

接下来,我们将使用Apache Commons Codec包来实现相同的功能;它基于RFC 2045,并且早于我们之前讨论过的Java 8实现。因此,当我们需要支持多个JDK版本(包括旧版本)或供应商时,它作为第三方API非常方便。

4.1 Maven

为了能够使用Apache库,我们需要在pom.xml中添加依赖:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.16.0</version>
</dependency>

上述内容的最新版本可以在Maven Central上找到。

4.2 编码

步骤与Java 8相同,只是这次我们将原始字节传递给org.apache.commons.codec.binary.Base64类的encodeBase64方法:

byte[] inFileBytes = Files.readAllBytes(Paths.get(IN_FILE));
byte[] encoded = org.apache.commons.codec.binary.Base64.encodeBase64(inFileBytes);

4.3 流编码

该库不支持流编码。

4.4 解码

再次,我们只需调用decodeBase64方法并将结果写入文件:

byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(encoded);

FileOutputStream fos = new FileOutputStream(OUT_FILE);
fos.write(decoded);
fos.flush();
fos.close();

5. 测试

现在我们将使用一个简单的JUnit测试来测试我们的编码和解码:

public class EncodeDecodeUnitTest {

    private static final String IN_FILE = // path to file to be encoded from;
    private static final String OUT_FILE = // path to file to be decoded into;
    private static byte[] inFileBytes;

    @BeforeClass
    public static void fileToByteArray() throws IOException {
        inFileBytes = Files.readAllBytes(Paths.get(IN_FILE));
    }

    @Test
    public void givenJavaBase64_whenEncoded_thenDecodedOK() throws IOException {
        byte[] encoded = java.util.Base64.getEncoder().encode(inFileBytes);
        byte[] decoded = java.util.Base64.getDecoder().decode(encoded);
        writeToFile(OUT_FILE, decoded);

        assertNotEquals(encoded.length, decoded.length);
        assertEquals(inFileBytes.length, decoded.length);
        assertArrayEquals(decoded, inFileBytes);
    }

    @Test
    public void givenJavaBase64_whenEncodedStream_thenDecodedStreamOK() throws IOException {
        try (OutputStream os = java.util.Base64.getEncoder().wrap(new FileOutputStream(OUT_FILE));
             FileInputStream fis = new FileInputStream(IN_FILE)) {
            byte[] bytes = new byte[1024];
            int read;
            while ((read = fis.read(bytes)) > -1) {
                os.write(bytes, 0, read);
            }
        }

        byte[] encoded = java.util.Base64.getEncoder().encode(inFileBytes);
        byte[] encodedOnDisk = Files.readAllBytes(Paths.get(OUT_FILE));
        assertArrayEquals(encoded, encodedOnDisk);

        byte[] decoded = java.util.Base64.getDecoder().decode(encoded);
        byte[] decodedOnDisk = java.util.Base64.getDecoder().decode(encodedOnDisk);
        assertArrayEquals(decoded, decodedOnDisk);
    }

    @Test
    public void givenApacheCommons_givenJavaBase64_whenEncoded_thenDecodedOK() throws IOException {
        byte[] encoded = org.apache.commons.codec.binary.Base64.encodeBase64(inFileBytes);
        byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(encoded);

        writeToFile(OUT_FILE, decoded);

        assertNotEquals(encoded.length, decoded.length);
        assertEquals(inFileBytes.length, decoded.length);

        assertArrayEquals(decoded, inFileBytes);
    }

    private void writeToFile(String fileName, byte[] bytes) throws IOException {
        FileOutputStream fos = new FileOutputStream(fileName);
        fos.write(bytes);
        fos.flush();
        fos.close();
    }
}

可以看到,我们首先在@BeforeClass方法中读取输入字节,并在两个@Test方法中验证:

  • 编码和解码的字节数组的长度不同
  • inFileBytes和解码后的字节数组具有相同的长度和相同的内容

当然,我们也可以打开我们创建的解码后的PDF文件,看看其内容是否与我们输入的文件相同。

6. 总结

在本快速教程中,我们了解了有关Java的Base64实用程序的更多信息。

我们还介绍了使用Java 8和Apache Commons Codec将PDF转换为Base64或从Base64转换为PDF的代码示例,有趣的是,JDK实现比Apache实现快得多。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章