程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 關於Base64編碼

關於Base64編碼

編輯:C++入門知識

作者:唐風

Base 64是一種比較古老的編碼方式,在通信中非常常見。它實現很簡單。

What?

Base64是一種基於64個可打印字符來表示二進制數據的表示方法(來自維基)”。這句話我一開始沒有看懂,現在我用我懂的方式再解釋一下:我們可以把通信的數據流分為兩種,“二進制流”和“文本流”。(注意,後面的定義並不嚴謹)。文本流是指數據串是以“人類可讀的字符”組成的,數據流中出現的 0x00,0x0a,0x0d 等數據一般都是特殊的控制數據(文本結束,或是換行、或者是其它的),而不是數據本身。二進制流是任意的一串數據(每個字節可以是從 0x00 到 0xff 的值,而不限於字符)。Base64 編碼就是用可打印字符(A-Z,a-z,0-9,+/這64個“字符”)組成的“文本流”來表示任意的二進制流數據的一種編碼方法。也就是:任意的二進制流,通過base64編碼後會變成一串只由可見字符(A-Z,a-z,0-9,+/這64個“字符”)組成的文本數據流。

完整的base64定義可見參考RFC 1421和RFC 2045。

Why?

Base64有什麼用?!base 64編碼後的數據流會比原數據流更長(是原數據流長度的4/3,原因見How的部分),那為什麼還要用這種方式進行編碼呢?(一開始我很不理解的地方)

原因是:通信設備的種類繁多,設計各異,比如有些設備只能處理/傳輸7bit的數據,有些設備的通信模塊只能處理文本流,等等,為了保證在這些設備之間仍然能無障礙地進行任何二進制數據(8bit為單位)的通信,就把這些數據重新編碼成只由可打印字符組成的文本流。base64中選取的可打印字符幾乎在任何設備上都支持(字符集采用US-ASCII標准)。另外還常會見到的一個場景是,要求數據從控制台(或者其它輸入/輸出設備)輸入或是輸出,由於這些輸入輸出設備只支持文本操作或顯示,所以也需要把二進制數據流在可打印字符集之間進行轉換(編解碼)。

How?

Base64編碼其實很簡單。將二進制數據流每三個字符一組進行分組(24bit),分組後,將24bit分成4個6bit數據,為每6bit數據前加上2個bit的0,就會得到4個8bit數據(變成了4byte),每個byte的值都在0-63的范圍之間。然後按預先設定的轉換表,把這些值轉換成對應的可打印字符。

前文本中引用的維基百科內容說明得也比較清楚。

過程參考下圖:

vector<char> Bin2Base64(vector<uint8_t> const& _bin) {
    static char const convert_table[] = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    vector<char> output;
    output.reserve((_bin.size() * 4) / 3);

    auto con_3bytes_to_4bytes = [&](uint8_t const * _3bytes_bin_data) {
        output.push_back(convert_table[_3bytes_bin_data[0] >> 2]);
        output.push_back(convert_table[((_3bytes_bin_data[0] & 0x03) << 4) | ((_3bytes_bin_data[1] >> 4) & 0x0f)]);
        output.push_back(convert_table[((_3bytes_bin_data[1] << 2) & 0x3c) | (_3bytes_bin_data[2] >> 6)]);
        output.push_back(convert_table[_3bytes_bin_data[2] & 0x3f]);
    };

    auto i = 0u;
    for (; (i + 3) <= _bin.size(); i += 3) {
        con_3bytes_to_4bytes(&_bin[i]);
    }

    if (i != _bin.size()) {
        uint8_t left_data[3] = { 0 };
        std::copy(begin(_bin) + i, end(_bin), left_data);
        con_3bytes_to_4bytes(left_data);
        std::fill(rbegin(output), rbegin(output) + (3 - (_bin.size() % 3)), '=');
    }    

    return output;
}

vector<uint8_t> Base64ToBin(vector<char> const & _base64stream) {
    vector<uint8_t> output;
    output.reserve(_base64stream.size() * 3 / 4);

    static hash_map<char, uint8_t> convert_table = {
            { 'A', 0  }, { 'B', 1  }, { 'C', 2  }, { 'D', 3  }, { 'E', 4  }, { 'F', 5  }, { 'G', 6  }, { 'H', 7  },
            { 'I', 8  }, { 'J', 9  }, { 'K', 10 }, { 'L', 11 }, { 'M', 12 }, { 'N', 13 }, { 'O', 14 }, { 'P', 15 },
            { 'Q', 16 }, { 'R', 17 }, { 'S', 18 }, { 'T', 19 }, { 'U', 20 }, { 'V', 21 }, { 'W', 22 }, { 'X', 23 },
            { 'Y', 24 }, { 'Z', 25 }, { 'a', 26 }, { 'b', 27 }, { 'c', 28 }, { 'd', 29 }, { 'e', 30 }, { 'f', 31 },
            { 'g', 32 }, { 'h', 33 }, { 'i', 34 }, { 'j', 35 }, { 'k', 36 }, { 'l', 37 }, { 'm', 38 }, { 'n', 39 },
            { 'o', 40 }, { 'p', 41 }, { 'q', 42 }, { 'r', 43 }, { 's', 44 }, { 't', 45 }, { 'u', 46 }, { 'v', 47 },
            { 'w', 48 }, { 'x', 49 }, { 'y', 50 }, { 'z', 51 }, { '0', 52 }, { '1', 53 }, { '2', 54 }, { '3', 55 },
            { '4', 56 }, { '5', 57 }, { '6', 58 }, { '7', 59 }, { '8', 60 }, { '9', 61 }, { '+', 62 }, { '/', 63 },
            { '=', 0 },
    };

    auto i = 0u;
    for ( ; i < _base64stream.size(); i += 4) {
        auto const byte1 = convert_table[_base64stream[i]];
        auto const byte2 = convert_table[_base64stream[i + 1]];
        auto const byte3 = convert_table[_base64stream[i + 2]];
        auto const byte4 = convert_table[_base64stream[i + 3]];

        output.push_back((byte1 << 2) | (byte2 >> 4));
        output.push_back(((byte2 & 0x0f) << 4) | (byte3 >> 2));
        output.push_back(((byte3 & 0x03) << 6) | byte4);
    }

    output.erase(end(output) - count(rbegin(_base64stream), rbegin(_base64stream) + 4, '='),
                 end(output));

    return output;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved