Перейти к основному содержимому

Как конвертировать PDF в Base64 на Java?

· 5 мин. чтения

1. Обзор

В этом кратком руководстве мы увидим, как выполнять кодирование и декодирование файла PDF с помощью Base64 с использованием Java 8 и кодека Apache Commons .

Но сначала давайте кратко рассмотрим основы Base64.

2. Основы Base64

При отправке данных по сети нам нужно отправить их в двоичном формате. Но если мы отправим только 0 и 1 , разные протоколы транспортного уровня могут интерпретировать их по-разному, и наши данные могут быть повреждены во время передачи.

Итак, чтобы обеспечить переносимость и общие стандарты при передаче бинарных данных, на сцену вышел Base64 .

Поскольку и отправитель, и получатель понимают и соглашаются использовать стандарт, вероятность того, что наши данные будут потеряны или неверно истолкованы, значительно снижается.

Теперь давайте рассмотрим несколько способов применить это к PDF.

3. Преобразование с использованием Java 8

Начиная с Java 8, у нас есть утилита java.util.Base64 , которая предоставляет кодировщики и декодеры для схемы кодирования Base64. Он поддерживает типы Basic, URL-safe и MIME, как указано в RFC 4648 и RFC 2045 .

3.1. Кодирование

Чтобы преобразовать PDF в Base64 , нам сначала нужно получить его в байтах и передать через метод encode 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-файл в память, а затем кодировать весь документ в памяти, мы считываем до 1 КБ данных за раз и передаем эти данные через кодировщик в 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, чтобы добиться того же. Он основан на RFC 2045 и предшествует реализации Java 8, которую мы обсуждали ранее. Итак, когда нам нужно поддерживать несколько версий JDK (включая устаревшие) или поставщиков, это удобно в качестве стороннего API.

4.1. Мавен

Чтобы иметь возможность использовать библиотеку Apache, нам нужно добавить зависимость к нашему pom.xml :

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

Последнюю версию вышеперечисленного можно найти на Maven Central .

4.2. Кодирование

Шаги такие же, как и для Java 8, за исключением того, что на этот раз мы передаем исходные байты методу encodeBase64 класса org.apache.commons.codec.binary.Base64 :

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 .

Мы также видели примеры кода для преобразования PDF в и из Base64 с использованием Java 8 и кодека Apache Commons . Интересно, что реализация JDK намного быстрее, чем у Apache.

Как всегда, исходный код доступен на GitHub .