1. 概要
1.Base64とは:
Base64 は、インターネット上で 8 ビット バイト コードを送信するための最も一般的なエンコード方式の 1 つです。MIME の詳細な仕様については、RFC2045 ~ RFC2049 を確認してください。 Base64 エンコードを使用すると、HTTP 環境で長い識別情報を渡すことができます。たとえば、Java Persistence システム Hibernate では、Base64 を使用して長い一意の識別子 (通常は 128 ビット UUID) を文字列にエンコードし、HTTP フォームおよび HTTP GET URL のパラメーターとして使用されます。他のアプリケーションでは、バイナリ データを URL (非表示のフォーム フィールドを含む) 内に配置するのに適した形式にエンコードする必要があることがよくあります。現時点では、Base64 エンコードを使用すると、時間がかかるだけでなく、読み取り不能になります。つまり、エンコードされたデータは肉眼で直接見ることができなくなります。
2. はじめに:
標準 Base64 は、URL での直接送信には適していません。これは、URL エンコーダが標準 Base64 の「/」および「+」文字を「%XX」の形式に変更し、データベースに入力するときにこれらの「%」文字が存在するためです。 ANSI SQL では「%」記号がワイルドカード文字として使用されているため、さらに変換が必要です。
この問題を解決するには、URL 用に改良された Base64 エンコーディングを使用できます。これにより、末尾に「=」記号が埋め込まれず、標準 Base64 の「+」と「/」がそれぞれ「*」と「-」に変更されます。 , これにより、URL のエンコード、デコード、データベース保存時の変換が不要になり、その過程でエンコードされた情報の長さの増加が回避され、データベースやフォームなどのオブジェクト識別子の形式が統一されます。
正規表現用に改良された Base64 バリアントもあり、「+」と「/」を「!」と「-」に変更します。これは、「+」、「*」、および「[」と「]」の両方が特別な意味を持つ可能性があるためです。正規表現。
「+/」を「_-」または「._」(プログラミング言語で識別子名として使用)、「.-」(XML の Nmtoken に使用)、さらには「_ :」(名前用) に変更するバリアントもあります。 XML で)。
Base64 では、3 つの 8 ビット バイトごとに 4 つの 6 ビット バイト (3*8 = 4*6 = 24) に変換し、その後 2 つの上位ビット 0 を 6 ビットに追加して 4 つの 8 ビット バイトを形成する必要があります。つまり、変換された文字列は理論的には次のようになります。純正より1/3くらい長いです。
3. ルール:
このエンコーディングに関するルール:
①.3文字を4文字に変換します。
②.76文字ごとに改行文字を追加します。
③.最後のターミネータも処理する必要があります。
それは抽象的すぎませんか?心配しないでください。例を見てみましょう。
変換前:aaaaaabb ccccdddd eeffffff
変換後:00aaaaaa 00bbcccc 00ddddee 00ffffff
それは明らかですよね?上位 3 バイトは元のテキスト、下位 4 バイトは変換された Base64 エンコーディングであり、最初の 2 ビットは 0 です。
変換後、コード テーブルを使用して必要な文字列 (つまり、最終的な Base64 エンコーディング) を取得します。
2. Java 実装コードの例:
パブリック最終クラス BaseLENGTH = 255; 静的プライベート最終 int LOOKUPLENGTH = 24; 静的プライベート最終 int SIXTEENBIT = 16; = 6; 静的プライベート最終 int FOURBYTE = 4; int SIGN = -128; 静的プライベート最終文字 PAD = '='; 静的プライベート最終ブール値 fDebug = false; 静的最終プライベート char[] lookUpBase64Alphabet = 新しい char[LOOKUPLENGTH] ]; 静的 { for (int i = 0; i < BASELENGTH; i++) { Base64Alphabet[i] = -1; } for (int i = 'Z'; i >= 'A'; i--) {base64Alphabet[i] = (バイト) (i - 'A'); i = 'z'; i >= 'a'; i--) {base64Alphabet[i] = (バイト) (i - 'a' + 26) } for (int i = '9'; >= '0'; {base64Alphabet[i] = (バイト) (i - '0' + 52); Base64Alphabet['/'] = 63; int i = 0; i <= 25; i++) lookUpBase64Alphabet[i] = (char) ('A' + i); 26, j = 0; i++, j++) lookUpBase64Alphabet[i] = (char) ('a' + j); (int i = 52, j = 0; i++, j++ ) lookUpBase64Alphabet[i] = (char) ('0' + j); lookUpBase64Alphabet[62] = (char) '+'; lookUpBase64Alphabet[63] = (char) '/'; } protected static boolean isWhiteSpace(char octect) { return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); static boolean 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) ); } /** * 16 進オクテクトを Base64 にエンコードします * * @param binaryData * を含む配列binaryData * @return エンコードされた Base64 配列 */ public static String encode(byte[] binaryData) { if (binaryData == null) return null; int lengthDataBits = binaryData.length * EIGHTBIT; if (lengthDataBits == 0) { return "" ; } int より少ない 24 ビット = lengthDataBits % TWENTYFOURBITGROUP; int 数トリプレット = lengthDataBits / TWENTYFOURBITGROUP; int 数値カルテット = 24 ビット未満 != 0 : 数値トリプレット = (数値カルテット - 1) / 19 + 1; char encodedData[] = null バイト数= 0、l = 0、b1 = 0、 b2 = 0、b3 = 0; int dataIndex = 0; int i = 0; if (fDebug) { System.out.println("number of Triplets = " +numberTriplets); 0; ライン < 行数 - 1; ライン ++) { for (int quartet = 0; quartet < 19; quartet++) { b1 = binaryData[dataIndex++]; b2 = binaryData[dataIndex++]; b3 = binaryData[dataIndex++]; if (fDebug) { System.out.println("b1= " + b2 + ", b3= " + b3); } l = (バイト) (b2 & 0x0f); k = (バイト) (b1 & 0x03); ((b1 & SIGN) == 0) ? (バイト) (b1 >> 2) : (バイト) ((b1) >> 2 ^ 0xc0); バイト val2 = ((b2 & SIGN) == 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[(l << val3]; lookUpBase64Alphabet[b3 & 0x3f]; } encodedData[encodedIndex++] } for (; i <numberTriplets; i++) { b1 = binaryData[dataIndex++]; (fDebug) { System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); } l = (バイト) (b2 & 0x0f); バイト val1 = ((b1 & SIGN) = = 0) ? (バイト) (b1 >> 2) : (バイト) ((b1) >> 2 ^ 0xc0); ((b2 & SIGN) == 0) ? (バイト) (b2 >> 4) : (バイト) ((b2) >> 4 ^ 0xf0); バイト val3 = ((b3 & SIGN) == 0);バイト) (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) < 4))); } encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << val3] = lookUpBase64Alphabet[b3 & 0x3f];ビット グループ if (24 ビット未満 == 8 ビット) { b1 = binaryData[dataIndex]; k = (バイト) (b1 & 0x03) { System.out.println("b1=" + b1); " + (b1 >> 2)); } byte val1 = ((b1 & SIGN) == 0) ? (バイト) (b1 >> 2) : (バイト) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; encodedData[encodedIndex++] = PAD; if (24 ビット未満 == SIXTEENBIT) { b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex + 1]; l = (バイト) (b1 & 0x03); == 0) ? (バイト) (b1 >> 2) : (バイト) ((b1) >> 2 ^ 0xc0); バイト val2 = ((b2 & SIGN) == 0) ? (バイト) (b2 >> 4) : (バイト) ((b2) >> 4 ^ 0xf0); ; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex] = 0xa; return new String(encodedData); * @param binaryData * Base64 データを含むバイト配列 * @return 含まれる配列デコードされたデータ。 */ public static byte[] decode(String encoded) { if (encoded == null) return null; // 空白を削除 int len =removeWhiteSpace(base64Data) ); if (len % FOURBYTE != 0) { return null;// 4 で割り切れる必要があります } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) 新しいバイト [0] を返します; バイト b1 = 0、b2 = 0、b4 = 0、マーカー 1 = 0; d1 = 0、d2 = 0、d3 = 0、d4 = 0; int i = 0; = 0; int dataIndex = 0; decodedData = new byte[(numberQuadruple) * 3]; for (; i <numberQuadruple - 1; i++) { if (!isData((d1 =base64Data[dataIndex++])) || !isData ((d2 =base64Data[dataIndex++])) || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 =base64Data[dataIndex++]))) return null;// 「データなし」が見つかった場合は、単に null を返します b1 =base64Alphabet[d1] =base64Alphabet[d2]; = ベース64アルファベット[d3]; b4 = ベース64アルファベット[d4]; = (バイト) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (バイト) (((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]; ; d3 = ベース64データ[データインデックス++]; d4 = ベース64データ[データインデックス++]; (!isData((d3)) || !isData((d4))) {// PAD 文字かどうかを確認します if (isPad(d3) && isPad(d4)) { // 2 つの 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] = (b1 << 2 | b2 >> 4); else if (!isPad( d3) && isPad(d4)) { // 1 つの PAD 例: 3cQ[Pad] b3 = Base64Alphabet[d3]; if ((b3 & 0x3) != 0)// 最後の 2 ビットはゼロでなければなりません return null; byte[] tmp = new byte[i * 3 + 2]; tmp, 0, i * 3); tmp[encodedIndex++] = (バイト) (b1 << 2 | b2 >> 4); tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); return tmp;// のようなエラー3c[Pad]r", "3cdX", "3cXd", "3cXX" // X はデータではありません } } else { // PAD はありません 例3cQl b3 = Base64Alphabet[d3]; b4 = Base64Alphabet[d4] = (バイト) (b1 << 2 | b2 >> 4); << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); } return decodedData; } /** * エンコードされた Base64 データを含む MIME から WhiteSpace を削除します。 * * @param data * Base64 データのバイト配列。 ) * @return the new length */ 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]; public static void main(String[] args) { System.out.println(encode("中華人民共和国".getBytes()));