1. Обзор
1.Что такое Base64:
Base64 — один из наиболее распространенных методов кодирования для передачи 8-битных байтовых кодов в Интернете. Вы можете проверить RFC2045~RFC2049, в котором есть подробные спецификации MIME. Кодировку Base64 можно использовать для передачи более длинной идентификационной информации в среде HTTP. Например, в системе Java Persistence Hibernate Base64 используется для кодирования длинного уникального идентификатора (обычно 128-битного UUID) в строку, которая используется в качестве параметров в формах HTTP и URL-адресах HTTP GET. В других приложениях часто необходимо закодировать двоичные данные в форму, подходящую для размещения в URL-адресе (включая скрытые поля формы). В настоящее время использование кодировки Base64 не только короче, но и нечитабельно, то есть закодированные данные не будут видны невооруженным глазом.
2. Введение:
Стандартный Base64 не подходит для передачи непосредственно в URL, поскольку кодировщик URL изменит символы «/» и «+» в стандартном Base64 на форму «%XX», и эти символы «%» существуют при входе в базу данных. , требуется дальнейшее преобразование, поскольку знак «%» использовался в качестве подстановочного знака в ANSI SQL.
Чтобы решить эту проблему, можно использовать улучшенную кодировку Base64 для URL-адресов, которая не дополняет знак «=» в конце и заменяет «+» и «/» в стандартном Base64 на «*» и «-» соответственно. , Это исключает необходимость преобразования при кодировании, декодировании и хранении URL-адресов в базе данных, позволяет избежать увеличения длины кодируемой информации в процессе, а также унифицирует формат идентификаторов объектов в базах данных, формах и т.п.
Существует также улучшенный вариант Base64 для регулярных выражений, в котором «+» и «/» заменяются на «!» и «-», поскольку «+», «*» и «Оба [» и «]» могут иметь особое значение в регулярные выражения.
Существуют также варианты, в которых «+/» заменяется на «_-» или «._» (используется в качестве имен идентификаторов в языках программирования) или «.-» (используется для Nmtokens в XML) или даже «_ :» (для имени в XML).
Base64 требует преобразования каждых трех 8-битных байтов в четыре 6-битных байта (3*8 = 4*6 = 24), а затем добавления двух старших 0 к 6-битным байтам, чтобы сформировать четыре 8-битных байта, то есть, скажем, преобразованная строка теоретически будет На 1/3 длиннее оригинального.
3. Правила:
Правила об этой кодировке:
①.Преобразуйте 3 символа в 4 символа..
②.Добавляйте символ новой строки каждые 76 символов.
③.Последний терминатор также должен быть обработан.
Не слишком ли это абстрактно? Не волнуйтесь, давайте посмотрим на пример:
Перед преобразованием: aaaaaabb ccccdddd eeffffff
После преобразования: 00aaaaaa 00bbcccc 00ddddee 00ffffff
Это должно быть ясно, не так ли? Верхние три байта — это исходный текст, а нижние четыре байта — преобразованная кодировка Base64, причем первые два бита равны 0.
После преобразования мы используем таблицу кодов, чтобы получить нужную строку (то есть окончательную кодировку Base64).
2. Пример кода реализации Java:
общественный окончательный класс Base64 {статический частный окончательный интервал BASELENGTH = 255; статический частный окончательный интервал LOOKUPLENGTH = 64 статический частный окончательный интервал TWENTYFOURBITGROUP = 24; статический частный окончательный интервал SIXTEENBIT = 16; = 6 статический частный финал int FOURBYTE = 4; статический частный финал; int SIGN = -128; статический частный окончательный символ PAD = '='; статический частный окончательный логический fDebug = false; статический окончательный частный байт [] base64Alphabet = новый байт [BASELENGTH]; ]; static { for (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = -1; } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (byte) (i - 'A' } for (int); я = 'z'; я >= 'а'; я--) { base64Alphabet[i] = (байт) (я - 'а' + 26 } for (int i = '9'; я); >= '0'; я--) { base64Alphabet[i] = (байт) (i - '0' + 52 } base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; int я = 0; я <= 25; я++) LookUpBase64Alphabet[i] = (символ) ('A' + я для (int я =); 26, j = 0; я <= 51; я++, j++) LookUpBase64Alphabet[i] = (char) ('a' + j for (int i = 52, j = 0; i <= 61; i++, j++); ) LookUpBase64Alphabet[i] = (символ) ('0' + j); LookUpBase64Alphabet[63] = (char) '/'; } protected static boolean isWhiteSpace(char Octect) { return (octect == 0x20 || Octect == 0xd || Octect == 0xa || Octect == 0x9 } protected; статическое логическое значение isPad(char Octect) { return (octect == PAD); } protected static boolean isData(char Octect) { return (base64Alphabet[octect] != -1 } protected static boolean isBase64(char Octect) { return (isWhiteSpace(octect) || isPad(octect) || isData(octect) ); } /** * Кодирует шестнадцатеричные октеты в Base64 * * @parambinaryData * Массив, содержащий binaryData * @return Закодированный массив Base64 */ public static String encode(byte[]binaryData) { if (binaryData == null) return null; int lengthDataBits =binaryData.length * EIGHTBIT; if (lengthDataBits == 0) { return "" } int lessThan24bits = lengthDataBits % TWENTYFOURBITGROUP; TWENTYFOURBITGROUP; int NumberQuartet = lessThan24bits!= 0 ? NumberTriplets + 1: int NumberLines = (numberQuartet - 1) / 19 + 1; char encodedData [] = null; = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0; int i = 0; if (fDebug) { System.out.println("количество троек = " + numberTriplets } for (int line =); 0; линия <numberLines - 1; строка++) { for (int квартет = 0; квартет < 19; квартет++) { b1 = binaryData[dataIndex++]; b2 =binaryData[dataIndex++]; if (fDebug) { System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); } l = (байт) (b2 и 0x0f); k = (байт) (b1 и 0x03); ((b1 & ЗНАК) == 0) ? (байт) (b1 >> 2) : (байт) ((b1) >> 2 ^ 0xc0 байт val2 = ((b2 & ЗНАК) == 0) ? байт) (b2 >> 4): (байт) ((b2) >> 4 ^ 0xf0 байт val3 = ((b3 & SIGN) ==); 0) ? (байт) (b3 >> 6): (байт) ((b3) >> 6 ^ 0xfc); if (fDebug) { System.out.println("val2 = " + val2); println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k << 4))) }; encodedData[encodedIndex++] = LookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = LookUpBase64Alphabet[val2 | (k << 4)]; LookUpBase64Alphabet[b3 & 0x3f]; i++; } encodedData[encodedIndex++] = 0xa; } for (; i <numberTriplets; i++) { b1 =binaryData[dataIndex++]; b3 =binaryData[dataIndex++]; (fDebug) { System.out.println("b1=" + b1 + ", b2=" + b2 + ", b3=" + b3); } l = (байт) (b2 & 0x0f); k = (байт) (b1 & 0x03); байт val1 = ((b1 & SIGN) = = 0) ? (байт) (b1 >> 2): (байт) ((b1) >> 2 ^ 0xc0 байт val2 =); ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); байт) (b3 >> 6): (байт) ((b3) >> 6 ^ 0xfc); if (fDebug) { System.out.println("val2 = " + val2); System.out.println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k <) < 4))); } encodedData[encodedIndex++] = LookUpBase64Alphabet[val1] = LookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = LookUpBase64Alphabet[(l << 2) | encodedData[encodedIndex++] = LookUpBase64Alphabet[b3 & 0x3f] } // формируем целое число 6- битовые группы, если (меньше, чем 24 бита == ВОСЕМЬ БИТ) { b1 =binaryData[dataIndex]; k = (byte) (b1 & 0x03); if (fDebug) { System.out.println("b1=" + b1); System.out.println("b1<<2 = " + (b1 >> 2)); } byte val1 = ((b1 & SIGN) == 0) ? (байт) (b1 >> 2): (байт) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex++] = LookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = LookUpBase64Alphabet[k << 4]; encodedData[encodedIndex++] = PAD; если (меньше, чем 24 бита == ШЕСТИНЬБИТ) { b1 = двоичныеДанные[индекс данных]; b2 = двоичныеданные[индекс данных + 1]; l = (байт) (b2 и 0x0f); k = (байт) (b1 и 0x03 байт val1 = ((b1 & SIGN) == 0) ? (байт) (b1 >> 2): (байт) ((b1) >> 2 ^ 0xc0); байт val2 = ((b2 & SIGN) == 0) ? (байт) (b2 >> 4) : (байт) ((b2) >> 4 ^ 0xf0); encodedData[encodedIndex++] = LookUpBase64Alphabet[val1] ; encodedData[encodedIndex++] = LookUpBase64Alphabet[val2 | 4)]; encodedData[encodedIndex++] = LookUpBase64Alphabet[l << 2]; encodedData[encodedIndex++] = PAD; } encodedData[encodedIndex] = 0xa; return new String(encodedData); * @parambinaryData * Массив байтов, содержащий данные Base64 * @return Массив, содержащий декодированные данные. */ public static byte[] decode(String encoded) { if (encoded == null) return null; char[] base64Data = encoded.toCharArray(); // удаляем пробелы int len = RemoveWhiteSpace(base64Data). ); if (len % FOURBYTE != 0) { return null;// должно делиться на четыре } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) вернуть новый байт[0]; байт decodedData[] = null; байт b1 = 0, b2 = 0, b3 = 0, b4 = 0, маркер0 = 0, маркер1 = 0; d1 = 0, d2 = 0, d3 = 0, d4 = 0 int i = 0; int encodedIndex; = 0; int dataIndex = 0; decodedData = новый байт[(numberQuadruple) * 3]; for (; i <numberQuadruple - 1; i++) { if (!isData((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++])) || base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) return null;// если обнаружено «нет данных», просто верните null b1 = base64Alphabet[d1]; b2 = base64Alphabet[d2]; = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++]; = (байт) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); encodedIndex++] = (байт) (b3 << 6 | b4 } if (!isData((d1 =); base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { return null;// если обнаружено «нет данных», просто верните null } b1 = base64Alphabet[d1]; b2 = base64Alphabet[d2] ; d3 = base64Data[dataIndex++]; d4 = base64Data[dataIndex++]; (!isData((d3)) || !isData((d4))) {// Проверяем, являются ли они символами PAD if (isPad(d3) && isPad(d4)) { // Два PAD, например 3c[Pad][ Pad] if ((b2 & 0xf) != 0)// последние 4 бита должны быть равны нулю, return null byte[] tmp = new byte[i * 3 + 1]; System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); return tmp; d3) && isPad(d4)) { // Один PAD, например 3cQ[Pad] b3 = base64Alphabet[d3]; if ((b3 & 0x3) != 0)// последние 2 бита должны быть равны нулю, возвращаем null; byte[] tmp = new byte[i * 3 + 2]; System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex++] = (байт) (b1 << 2 | b2 >> 4); tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); return tmp; } else { return null;// ошибка типа " 3c[Pad]r", "3cdX", "3cXd", "3cXX" // где X не является данными } } else { // Нет PAD, например 3cQl b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++] = (байт) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (байт) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); } return decodedData; } /** * удалить WhiteSpace из MIME, содержащего закодированные данные Base64 * * @param data * массив байтов данных Base64 (с WS). ) * @return новую длину */ protected static int RemoveWhiteSpace(char[] data) { if (data == null) return 0 // считать символы, которые не являются таковыми; пробел int newSize = 0; int len = data.length; for (int i = 0; i < len; i++) { if (!isWhiteSpace(data[i])) data[newSize++] = data[i]; } return newSize; } public static void main(String[] args) { System.out.println(encode("Китайская Народная Республика".getBytes())) }};