Вступление
Процесс преобразования данных с применением некоторых методов / правил в новый формат называется кодированием . Декодирование - это процесс, обратный кодированию - возвращение закодированных данных к исходному формату.
Кодирование существует повсюду, и компьютеры в значительной степени полагаются на различные форматы кодирования для доставки и передачи информации.
От последнего изображения кошки в вашей ленте до голосового сообщения, которое вы прослушали в приложении для обмена сообщениями - все они были закодированы на стороне отправителя, доставлены вам и декодированы на стороне получателя.
Кодирование гарантирует, что данные останутся нетронутыми и эффективными для транспортировки.
Что такое Base64?
Base64 - это схема кодирования двоичного кода в текст. Он представлен в виде печатаемых символов ASCII, где каждый символ Base64 содержит 6 бит двоичной информации.
Это очень полезно для хранения информации об изображениях / аудио в строках информации. Чем не является Base64, так это алгоритмом шифрования.
Хотя он в некоторой степени «скрывает» данные, это ни в коем случае не является безопасным форматом.
Как работает Base64?
В Base64, как следует из названия, для кодирования двоичных данных используются 64 символа. Вот эти персонажи:
- 26 заглавных букв [AZ]
- 26 строчных букв [az]
- 10 цифр [0–9]
- 2 специальных символа [+, /]
Примечание. Существует также 65-й символ ( =
), который имеет
особое значение и называется символом заполнения .
Как обычно, когда дело касается компьютеров, числа представлены в
степени 2. Таким образом, 64 символа Base64 можно записать как:
$
64 = 2 ^ 6
$
Каждый символ представлен 6 битами. Вы можете пойти выше и сделать
так, чтобы каждый символ представлял 8 бит. Это будет Base256. Хотя это
непрактично из-за трудностей в процессе кодирования / декодирования.
Давайте продолжим и вручную закодируем простую строку, чтобы получить хорошее представление о том, как работает этот процесс.
Ручное кодирование
Например, предположим, что у нас есть строка - ABC123
которую мы хотим
закодировать в Base64. В ходе этого процесса мы делаем пять шагов:
- Отдельно возьмем значения ASCII входных символов:
Персонаж А B C 1 2 3 ASCII (десятичный) 65 66 67 49 50 51
- Преобразуйте десятичное значение каждого символа в 8-битное двоичное:
Персонаж А B C 1 2 3 ASCII 65 66 67 49 50 51 Двоичный 01000001 01000010 01000011 00110001 00110010 00110011
-
Измените порядок двоичных чисел на блоки по 6 бит:
010000 010100 001001 000011 001100 010011 001000 110011
Если это невозможно разбить его на куски шесть, мы должны пэда последовательность.
-
Получите десятичные значения этих двоичных фрагментов:
Двоичный 010000 010100 001001 000011 001100 010011 001000 110011 Десятичный 16 20 9 3 12 19 8 51
- Наконец, используя диаграмму Base64, преобразуйте каждое десятичное число в символ Base64:
Значение Char Значение Char Значение Char Значение Char 0 А 16 Q 32 грамм 48 ш 1 B 17 р 33 час 49 Икс 2 C 18 S 34 я 50 y 3 D 19 Т 35 год j 51 z 4 E 20 U 36 k 52 0 5 F 21 год V 37 л 53 1 6 грамм 22 W 38 м 54 2 7 ЧАС 23 Икс 39 п 55 3 8 я 24 Y 40 о 56 4 9 J 25 Z 41 год п 57 5 10 K 26 а 42 q 58 6 11 L 27 б 43 год р 59 7 12 M 28 год c 44 год s 60 8 13 N 29 d 45 т 61 9 14 О 30 е 46 ты 62 + 15 п 31 год ж 47 v 63 /
В конце концов, у нас осталась строка QUJDMTIz
- представление
ABC123
в формате Base64.
Примечание: 6 входных символов кодируются в конце в 8 символов. Это означает, что для хранения строки в кодировке Base64 требуется на ~ 33% больше места, чем для исходной строки.
Зачем использовать кодировку Base64?
Компьютеры работают с
0
с и1
с, так зачем преобразовывать это в другой формат?
Да, верно. Двоичный - это язык компьютеров. Именно поэтому мы его
конвертируем. Последовательность, такая как 0010110
может означать
многое. Это может быть часть изображения, часть аудиофайла или команда,
удаляющая половину вашего жесткого диска.
Эти данные должны обрабатываться по-разному, в зависимости от того, что они должны представлять. Кроме того, многие серверы не ожидают необработанных двоичных данных. Например, почтовые серверы ожидают текстовые данные. Все электронные письма кодируются перед их отправкой приложениями.
Кодирование строк с помощью Java 8 - Base64
Java 8 познакомила нас с новым классом -
Base64
. Он поддерживает кодирование и декодирование нескольких типов вариантов
данных, как указано в RFC 2045 и
RFC 4648 :
- Базовый
- URL и имя файла безопасны
- MIME
Базовое кодирование и декодирование строк
Используя базовый кодировщик, мы можем закодировать строку в Base64. Базовый кодировщик не добавляет символ-разделитель строк.
Если длина строки не делится на 3 (8-битное представление не может быть
объединено в 6-битные группы), заполнение будет добавлено в виде =
в
конце:
Encoder encoder = Base64.getEncoder();
String originalString = "basic";
String encodedString = encoder.encodeToString(originalString.getBytes());
System.out.println(encodedString);
Base64
- это фабричный класс, из которого мы получаем различные
реализации / варианты кодировщика. Метод encodeToString()
наш ввод в
представление ввода Base64 и упакует его в строку. Вы также можете
использовать метод encode()
чтобы вместо этого кодировать его в поток
byte
ByteBuffer
При необходимости вы также можете вернуть экземпляр кодировщика, который
не будет withoutPadding()
при его создании из фабричного класса:
Base64.getEncoder().withoutPadding();
Примечание. Кодирование без заполнения, скорее всего, приведет к тому, что строка Base64 не может быть декодирована обратно, поскольку часть информации потеряна.
Выполнение примера кода даст:
YmFzaWM=
Закодировав нашу строку, давайте также создадим экземпляр Decoder
и
декодируем созданную строку. Но декодеры работают только с byte
массивами:
Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode(encodedString);
System.out.println(new String(bytes));
Этот код приведет к:
basic
Кодирование и декодирование URL
Для кодирования и декодирования URL-адресов мы можем использовать
экземпляр Encoder
и Decoder
которые используют безопасный тип Base64
для URL-адреса и имени файла. Они также не добавляют символ разделителя
строк.
Мы получаем их с помощью getUrlEncoder()
и getUrlDecoder()
через
фабрику Base64
Encoder encoder = Base64.getUrlEncoder();
String originalinput = "https://stackabuse.com/tag/java/";
String encodedUrl = encoder.encodeToString(originalinput.getBytes());
System.out.println(encodedUrl);
Как и раньше, метод encodeToString()
ввод и упакует его в строку:
aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=
Метод encode()
кодирует ввод в массив byte
Опять же, метод
decode()
работает с byte
массивом и декодирует строку Base64 в
исходную:
Decoder decoder = Base64.getUrlDecoder();
byte[] bytes = decoder.decode(encodedUrl);
System.out.println(new String(bytes));
Выполнение этого кода дает:
https://stackabuse.com/tag/java/
Примечание . В этой схеме доступны три специальных символа: +
,
/
, =
. Эти символы могут иметь различное значение в URL-адресах и
некоторых файловых системах и могут вызвать проблему, если используется
закодированная строка. Чтобы избежать этих проблем, URL-адреса и строки
файлов должны кодироваться и декодироваться с помощью декодера,
безопасного для URL-адресов.
+
и /
заменяются на -
и _
соответственно.
Кодирование и декодирование MIME
Метки многоцелевого расширения почты Интернета (MIME) используются для определения типа носителя (HTML, аудио, видео).
Поскольку многие типы мультимедиа, такие как изображения, документы и т. Д., Отправляются в виде вложений по электронной почте, необходимо закодировать их в формате, приемлемом для всех протоколов.
При отправке вложений, таких как .txt
, они кодируются в Base64 и
прикрепляются к электронному письму. Вот как может выглядеть вложение:
Content-Type: text/plain;
name="log_attachment.txt"
Content-Disposition: attachment;
filename="attachment.txt"
Content-Transfer-Encoding: base64
TUlNRS1WZXJzaW9uOiAxLjANClgtTWFpbGVyOiBNYWlsQmVlLk5FVCA4LjAuNC40MjgNClN1Ympl
Y3Q6IHRlc3Qgc3ViamVjdA0KVG86IGtldmlubUBkYXRhbW90aW9uLmNvbQ0KQ29udGVudC1UeXBl
OiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQoJYm91bmRhcnk9Ii0tLS09X05leHRQYXJ0XzAwMF9B
RTZCXzcyNUUwOUFGLjg4QjdGOTM0Ig0KDQoNCi0tLS0tLT1fTmV4dFBhcnRfMDAwX0FFNkJfNzI1
RTA5QUYuODhCN0Y5MzQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCgljaGFyc2V0PSJ1dGYt
OCINCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KdGVzdCBi
b2R5DQotLS0tLS09X05leHRQYXJ0XzAwMF9BRTZCXzcyNUUwOUFGLjg4QjdGOTM0DQpDb250ZW50
LVR5cGU6IHRleHQvaHRtbDsNCgljaGFyc2V0PSJ1dGYtOCINCkNvbnRlbnQtVHJhbnNmZXItRW5j
b2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KPHByZT50ZXN0IGJvZHk8L3ByZT4NCi0tLS0tLT1f
TmV4dFBhcnRfMDAwX0FFNkJfNzI1RTA5QUYuODhCN0Y5MzQtLQ0K
При кодировании MIME вывод форматируется так, чтобы быть дружественным к
MIME - строки не могут содержать более 76 символов, и каждая строка
заканчивается на \r\n
, за исключением последней, естественно. \r
-
это символ возврата каретки, а \n
- это символ новой строки.
Создадим файл с именем file.txt
который содержит:
"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”
Ozymandias, by Percy Bysshe Shelley
Теперь давайте прочитаем байты файла и упакуем их в byte
массив, после
чего мы его закодируем:
byte[] bytes = Files.readAllBytes(Paths.get("path/to/file"));
String encodedString = Base64.getMimeEncoder().encodeToString(bytes);
System.out.println(encodedString);
Этот код даст нам:
IkkgbWV0IGEgdHJhdmVsbGVyIGZyb20gYW4gYW50aXF1ZSBsYW5kLA0KV2hvIHNhaWTigJTigJxU
d28gdmFzdCBhbmQgdHJ1bmtsZXNzIGxlZ3Mgb2Ygc3RvbmUNClN0YW5kIGluIHRoZSBkZXNlcnQu
Li4uIE5lYXIgdGhlbSwgb24gdGhlIHNhbmQsDQpIYWxmIHN1bmsgYSBzaGF0dGVyZWQgdmlzYWdl
IGxpZXMsIHdob3NlIGZyb3duLA0KQW5kIHdyaW5rbGVkIGxpcCwgYW5kIHNuZWVyIG9mIGNvbGQg
Y29tbWFuZCwNClRlbGwgdGhhdCBpdHMgc2N1bHB0b3Igd2VsbCB0aG9zZSBwYXNzaW9ucyByZWFk
DQpXaGljaCB5ZXQgc3Vydml2ZSwgc3RhbXBlZCBvbiB0aGVzZSBsaWZlbGVzcyB0aGluZ3MsDQpU
aGUgaGFuZCB0aGF0IG1vY2tlZCB0aGVtLCBhbmQgdGhlIGhlYXJ0IHRoYXQgZmVkOw0KQW5kIG9u
IHRoZSBwZWRlc3RhbCwgdGhlc2Ugd29yZHMgYXBwZWFyOg0KTXkgbmFtZSBpcyBPenltYW5kaWFz
LCBLaW5nIG9mIEtpbmdzOw0KTG9vayBvbiBteSBXb3JrcywgeWUgTWlnaHR5LCBhbmQgZGVzcGFp
ciENCk5vdGhpbmcgYmVzaWRlIHJlbWFpbnMuIFJvdW5kIHRoZSBkZWNheQ0KT2YgdGhhdCBjb2xv
c3NhbCBXcmVjaywgYm91bmRsZXNzIGFuZCBiYXJlDQpUaGUgbG9uZSBhbmQgbGV2ZWwgc2FuZHMg
c3RyZXRjaCBmYXIgYXdheS7igJ0NCg0KT3p5bWFuZGlhcywgYnkgUGVyY3kgQnlzc2hlIFNoZWxs
ZXk=
Естественно, что расшифровать этот контент так же просто, как:
Decoder decoder = Base64.getMimeDecoder();
byte[] decodedBytes = decoder.decode(encodedString);
System.out.println(new String(decodedBytes));
Этот код даст:
"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”
Ozymandias, by Percy Bysshe Shelley
Apache Commons
Из-за его полезности и распространенности в Java многие проекты имеют Apache Commons, включенные в путь к классам. Это отличная библиотека со множеством полезных функций, часто используемых в производстве, и кодирование / декодирование не исключение.
Используя Maven, добавить его в свой проект так же просто, как включить зависимость:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${version}</version>
</dependency>
Или, если вы используете Gradle:
compile group: 'commons-codec', name: 'commons-codec', version: '${version}'
Подобно официальной реализации Java, Base64
является основным API.
Хотя вместо того, чтобы использоваться в качестве фабрики для Encoder
/ Decoder
, сам класс обрабатывает все кодирование и декодирование.
Другие полезные методы, которые он предоставляет, - это такие методы,
как isBase64()
, isInAlphabet()
и isUrlSafe()
.
Базовое кодирование и декодирование строк Apache Commons
Давайте продолжим и закодируем простую строку в Base64. Метод
encodeBase64()
принимает byte
массив и возвращает byte
массив,
представляющий закодированный ввод.
String inputString = "Some String";
byte[] bytes = Base64.encodeBase64(inputString.getBytes());
System.out.println(new String(bytes));
Запуск этого кода даст:
U29tZSBTdHJpbmc=
В качестве альтернативы вы можете использовать метод
encodeBase64String()
, который вернет строку вместо массива byte
String inputString = "Some String";
String encodedString = Base64.encodeBase64String(inputString.getBytes());
System.out.println(encodedString);
Запуск этого кода даст:
U29tZSBTdHJpbmc=
В том же духе Base64
используется в качестве декодера. Он принимает
byte
массив или String и возвращает byte
массив:
String decodedString = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedString);
// Or
String anotherDecodedString = new String(Base64.decodeBase64(encodedString));
System.out.println(anotherDecodedString);
Запуск этого кода даст:
Some String
Some String
Кодирование и декодирование URL-адресов Apache Commons
Кодирование и декодирование URL-адресов происходит по тому же принципу:
String originalInput = "https://stackabuse.com/tag/java/";
byte[] bytes = Base64.encodeBase64URLSafe(originalInput.getBytes());
System.out.println(new String(bytes));
Выполнение этого приведет к:
aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=
Вы также можете вернуть String вместо массива byte
String originalInput = "https://stackabuse.com/tag/java/";
String encodedString = Base64.encodeBase64URLSafeString(originalInput.getBytes());
System.out.println(encodedString);
encodedString
:
aHR0cHM6Ly9zdGFja2FidXNlLmNvbS90YWcvamF2YS8=
И, наконец, мы также можем декодировать представление URL-адреса в формате Base64:
String decodedUrl = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedUrl);
// Or
String anotherDecodedUrl = Base64.decodeBase64(encodedString);
System.out.println(anotherDecodedUrl);
https://stackabuse.com/tag/java/
https://stackabuse.com/tag/java/
Кодирование и декодирование MIME Apache Commons
Кодирование и декодирование типов MIME немного отличается от официальной
реализации Java. На этот раз мы используем метод encodeBase64Chunked()
:
byte[] bytes = Files.readAllBytes(Paths.get("path/to/file"));
String encodedString = new String(Base64.encodeBase64Chunked(bytes));
System.out.println(encodedString);
Этот код приводит к:
IkkgbWV0IGEgdHJhdmVsbGVyIGZyb20gYW4gYW50aXF1ZSBsYW5kLA0KV2hvIHNhaWTigJTigJxU
d28gdmFzdCBhbmQgdHJ1bmtsZXNzIGxlZ3Mgb2Ygc3RvbmUNClN0YW5kIGluIHRoZSBkZXNlcnQu
Li4uIE5lYXIgdGhlbSwgb24gdGhlIHNhbmQsDQpIYWxmIHN1bmsgYSBzaGF0dGVyZWQgdmlzYWdl
IGxpZXMsIHdob3NlIGZyb3duLA0KQW5kIHdyaW5rbGVkIGxpcCwgYW5kIHNuZWVyIG9mIGNvbGQg
Y29tbWFuZCwNClRlbGwgdGhhdCBpdHMgc2N1bHB0b3Igd2VsbCB0aG9zZSBwYXNzaW9ucyByZWFk
DQpXaGljaCB5ZXQgc3Vydml2ZSwgc3RhbXBlZCBvbiB0aGVzZSBsaWZlbGVzcyB0aGluZ3MsDQpU
aGUgaGFuZCB0aGF0IG1vY2tlZCB0aGVtLCBhbmQgdGhlIGhlYXJ0IHRoYXQgZmVkOw0KQW5kIG9u
IHRoZSBwZWRlc3RhbCwgdGhlc2Ugd29yZHMgYXBwZWFyOg0KTXkgbmFtZSBpcyBPenltYW5kaWFz
LCBLaW5nIG9mIEtpbmdzOw0KTG9vayBvbiBteSBXb3JrcywgeWUgTWlnaHR5LCBhbmQgZGVzcGFp
ciENCk5vdGhpbmcgYmVzaWRlIHJlbWFpbnMuIFJvdW5kIHRoZSBkZWNheQ0KT2YgdGhhdCBjb2xv
c3NhbCBXcmVjaywgYm91bmRsZXNzIGFuZCBiYXJlDQpUaGUgbG9uZSBhbmQgbGV2ZWwgc2FuZHMg
c3RyZXRjaCBmYXIgYXdheS7igJ0NCg0KT3p5bWFuZGlhcywgYnkgUGVyY3kgQnlzc2hlIFNoZWxs
ZXk=
Расшифровка такая же, как и раньше:
String decodedMime = new String(Base64.decodeBase64(encodedString.getBytes()));
System.out.println(decodedMime);
// Or
String anotherDecodedMime = Base64.decodeBase64(encodedString);
System.out.println(anotherDecodedMime);
Этот код приводит к:
"I met a traveller from an antique land,
Who said - “Two vast and trunkless legs of stone
Stand in the desert.... Near them, on the sand,
Half sunk a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them, and the heart that fed;
And on the pedestal, these words appear:
My name is Ozymandias, King of Kings;
Look on my Works, ye Mighty, and despair!
Nothing beside remains. Round the decay
Of that colossal Wreck, boundless and bare
The lone and level sands stretch far away.”
Ozymandias, by Percy Bysshe Shelley
Вспомогательные методы Apache Commons
В истинном стиле Apache Commons мы познакомились с несколькими
вспомогательными методами, которые сделают нашу жизнь немного проще.
Например, мы можем проверить, находится ли строка или byte
в
допустимом Base64:
String originalInput = "https://stackabuse.com/tag/java/";
byte[] bytes = Base64.encodeBase64URLSafe(originalInput.getBytes());
System.out.println(Base64.isBase64(bytes));
// Or
System.out.println(Base64.isBase64(encodedString));
Этот код приведет к:
true
true
Мы можем проверить, находимся ли мы в безопасном для URL-адресов режиме:
System.out.println(Base64.isUrlSafe());
Поскольку мы закодировали строку URL-адреса с помощью
encodeBase64URLSafe()
, этот код приводит к следующему:
true
И, наконец, мы можем проверить, находится ли каждый отдельный byte
из
нашего массива в алфавите Base64:
for (int i = 0; i < bytes.length; i++) {
System.out.println(Base64.isInAlphabet(bytes[i]));
}
Заключение
В этой статье мы углубились в то, что такое кодирование и декодирование, а затем сделали обзор Base64. Мы вручную закодировали строку, чтобы лучше понять процесс, предшествуя множеству примеров кода.
Использование Base64
в Java позволяет нам создавать различные типы
кодировщиков и декодеров, оптимизированных для кодирования и
декодирования базовых строк, URL-адресов и типов MIME.
Используя Base64
предоставленный Apache Commons, мы полагаемся на
базовый класс для непосредственного кодирования.