字符编码之Base64

博学,切问,近思--詹子知(http://blog.csdn.net/zhiqiangzhan

1.什么是Base64.

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。

它采用64个可见的基本字符去传输所有信息,因此即使被不同的编码颠来倒去的编码解码也不会造成数据丢失。

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

 

2.Base64的优势。

  1. 编码解码速度快。
  2. 具有一定的加密效果。
  3. 实现简单。
  4. 编码解码速度快。

3.实现原理。

Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,因此, 转换后的字节一定会落在区间[0-64)当中,故此可以找到对应基本字符表示此字节,转换后的字符串理论上将要比原来的长1/3。

我们来看一个例子。

转换前:10101111 01101011 11001101
转换后:00101011 00110110 00101111 00001101

 

 

编码转换规则:

  1. 用指定的编码对字符串进行解码,得到解码后的字节数组。
  2. 按照规则把每3个字节转换为4个Base64基本字符。
  3. 处理最后的字节
    • 剩余的字节为0,编码转换结束。
    • 剩余的字节为1,把当前字节按照规则转换为Base64前两个字符,后面两位用'='补齐,编码转换结束。
    • 剩余的字节为1,把当前字节按照规则转换为Base64前三个字符,最后一位用'='补齐,编码转换结束。
  4. 得到编码后的Base64 String。

解码转换规则:

  1. 准备好需要解码的Base64 String。
  2. 每4个一组,转换为对应的3个字节。
  3. 处理最后剩余的字符。
  4. 得到解码后的字节数组。

 

4.通用的编码传输解决方案。

  1. 使用UTF-8对需要传输的String进行编码,得到编码后的字节数组。
  2. 用Base64对字节数组进行编码,得到Base64 String。
  3. 传输编码后的Base64 String。
  4. 接收到传输到字节数组, 如果是字节数组,用本地编码对其进行解码即可,得到Base64 String。
  5. 用Base64对 Base64 String 进行解码,得到字节数组。
  6. 用UTF-8对字节数组进行解码,得到最终被传输的String。

5.Java 实现。

 public class Base64 {

/** The 64 valid Base64 characters */
private final static char[] BASE64_ALPHABET = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
'2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };

/** The BASE64 suffix code */
private static final byte SUFFIX_CODE = '=';

private Base64() {
}

/**
* Encode a byte array into BASE64 string.
*
* @param a the source byte array
* @return BASE64 string
*/
public static String encode(byte[] a) {
int length = a.length;
int numOfGroups = length / 3;
int remainingBytes = length - numOfGroups * 3;
int resultLength = 4 * ((length + 2) / 3);
char[] result = new char[resultLength];
int srcIndex = 0, dstIndex = 0;

for (int i = 0; i < numOfGroups; i++) {
int byte0 = a[srcIndex++] & 0xff;
int byte1 = a[srcIndex++] & 0xff;
int byte2 = a[srcIndex++] & 0xff;
result[dstIndex++] = BASE64_ALPHABET[byte0 >> 2];
result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30 | (byte1 >> 4)];
result[dstIndex++] = BASE64_ALPHABET[(byte1 << 2) & 0x3c | (byte2 >> 6)];
result[dstIndex++] = BASE64_ALPHABET[byte2 & 0x3f];
}

// Process the remaining bytes
if (remainingBytes > 0) {
int byte0 = a[srcIndex++] & 0xff;
result[dstIndex++] = BASE64_ALPHABET[byte0 >> 2];
if (remainingBytes == 1) {
result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30];
result[dstIndex++] = SUFFIX_CODE;
result[dstIndex++] = SUFFIX_CODE;
} else {
// remainingBytes == 2;
int byte1 = a[srcIndex++] & 0xff;
result[dstIndex++] = BASE64_ALPHABET[(byte0 << 4) & 0x30 | (byte1 >> 4)];
result[dstIndex++] = BASE64_ALPHABET[(byte1 << 2) & 0x3f];
result[dstIndex++] = SUFFIX_CODE;
}
}
return new String(result);
}

/**
* Decode a BASE64 string into byte array.
*
* @param s BASE64 string
* @return the original byte array
*/
public static byte[] decode(String s) {
if (s == null || s.length() == 0)
{
return null;
}

int length = s.length();
// length must be a multiple of 4
if (length % 4 != 0) {
throw new IllegalArgumentException("String length must be a multiple of four.");
}

int numOfGroups = length / 4;
int numOfFullGroups = numOfGroups;
int numOfPaddings = 0;
if (s.charAt(length - 1) == SUFFIX_CODE) {
numOfPaddings++;
numOfFullGroups--;
if (s.charAt(length - 2) == SUFFIX_CODE)
{
numOfPaddings++;
}
}
byte[] result = new byte[3 * numOfGroups - numOfPaddings];

int srcIndex = 0, dstIndex = 0;
for (int i = 0; i < numOfFullGroups; i++) {
int ch0 = getCharIndex(s.charAt(srcIndex++));
int ch1 = getCharIndex(s.charAt(srcIndex++));
int ch2 = getCharIndex(s.charAt(srcIndex++));
int ch3 = getCharIndex(s.charAt(srcIndex++));

result[dstIndex++] = (byte)((ch0 << 2) | (ch1 >> 4));
result[dstIndex++] = (byte)((ch1 << 4) | (ch2 >> 2));
result[dstIndex++] = (byte)((ch2 << 6) | ch3);
}

if (numOfPaddings != 0) {
int ch0 = getCharIndex(s.charAt(srcIndex++));
int ch1 = getCharIndex(s.charAt(srcIndex++));
result[dstIndex++] = (byte)((ch0 << 2) | (ch1 >> 4));
if (numOfPaddings == 1) {
int ch2 = getCharIndex(s.charAt(srcIndex++));
result[dstIndex++] = (byte)((ch1 << 4) | (ch2 >> 2));
}
}

return result;
}

/**
* Get the index of the character in the BASE64_ALPHABET array.
*
* @param c
* @return
*/
private static int getCharIndex(char c) {
if (c >= 'A' && c <= 'Z') { // A-Z: 65-90
return (int) c - 65;
} else if (c >= 'a' && c <= 'z') { // a-z: 97-122
return (int) c - 71;
} else if (c >= '0' && c <= '9') {// 0-9: 48-57
return (int) c + 4;
} else if (c == '+') {
return 62;
} else if (c == '/') {
return 63;
}
throw new IllegalArgumentException("Character " + c + " is not a BASE64 char");
}

public static void main(String[] args) {
String buf = encode("中国加油".getBytes());
System.out.println(buf);
byte[] result = decode(buf);
System.out.println(new String(result));
}

}
 

时间: 2024-10-21 07:37:00

字符编码之Base64的相关文章

在Python中使用base64模块处理字符编码的教程

  这篇文章主要介绍了在Python中使用base64模块处理字符编码的教程,示例代码基于Python2.x版本,需要的朋友可以参考下 Base64是一种用64个字符来表示任意二进制数据的方法. 用记事本打开exe.jpg.pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法.Base64是一种最常见的二进制编码方法. Base64的原理很简单,首先,准备一个包含64个字符

字符编码掠影:现代编码模型

Abstract 字符编码,在计算机导论中经常作为开门的前几个话题来讲,然而很多CS教材对这个话题基本都是走马观花地几页带过.导致了许多人对如此重要且基本的概念认识模糊不清.直到在实际编程中,尤其是遇到多语言.国际化的问题,被虐的死去活来之后才痛下决心去重新钻研.诸如此类极其基础却又容易被人忽视的的知识点还有:大小端表示,浮点数细节,正则表达式,日期时间处理等.本文是系列的第一篇,旨在阐明字符编码这个大坑中许多纠缠不清的概念. 基本概念 现代编码模型自底向上分为五个层次: 抽象字符表 ACR (

字符编码转化问题急需解决

问题描述 字符编码转化问题急需解决 AGwAaQBuAGeAdABl 说是:unicode的base64编码,说编码内容是:lingtu 但是我将 lingtu 写成unicoebase64为 bGluZ3R1 有人说是:还要进行大小端转化,但是这个怎么转化我不懂

JavaScript Unicode 字符编码详解教程

Unicode 是为了解决传统的字符编码方案的局限而产生的,例如ISO 8859所定义的字符虽然在不同的国家中广泛地使用,可是在不同国家间却经常出现不兼容的情况.很多传统的编码方式都有一个共同的问题,即容许电脑处理双语环境(通常使用拉丁字母以及其本地语言),但却无法同时支持多语言环境(指可同时处理多种语言混合的情况). 一.Unicode是什么? Unicode源于一个很简单的想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了. 它从0开始

文件名的字符编码和c的fopen函数问题

问题描述 文件名的字符编码和c的fopen函数问题 问一个问题,文件名的存储和文件名的显示应该是两回事吧 中文版windows的环境字符集是GBK GBK中"茅"的编码是 195 169(十进制) 如果我在中文版windows里看到个文件叫"a茅" 那么他的文件名在硬盘中的存储方式应该是97 195 169 我编了个c程序如下: FILE *fp; char b[100]={'a',195,169,0}; strcat(b,".html"); i

ajax代理程序,自动判断字符编码

ajax|编码|程序 由于ajax在跨域的访问上有问题,目前最好的方法是做代理.写了个代理程序和心得 为了做ajax的代理,研究了下服务器端的xmlhttp并和客户端的ajax中的xmlhttp做了个比较,后台代码是asp的 服务器端的xmlhttp也就是asp小偷程序,我把代码改成了javascript. 1.在服务器端的xmlhttp.Open("GET",url,false)异步必须是关闭的,而客户端的异步是打开的,这个很好理解. 2.在服务器端的xmlhttp.Response

ajax代理程序自动判断字符编码

ajax|编码|程序 由于ajax在跨域的访问上有问题,目前最好的方法是做代理.写了个代理程序和心得. 为了做ajax的代理,研究了下服务器端的xmlhttp并和客户端的ajax中的xmlhttp做了个比较,后台代码是asp的. 服务器端的xmlhttp也就是asp小偷程序,我把代码改成了javascript. 1.在服务器端的xmlhttp.Open("GET",url,false)异步必须是关闭的,而客户端的异步是打开的,这个很好理解.2.在服务器端的xmlhttp.Respons

tomcat下的jsp和servlet的字符编码问题

js|servlet|编码|问题 使用filter来改变request的编码 在前面的文章里面,我们讨论了在tomcat下的jsp和servlet的字符编码问题! 知道当没有指定request的编码的时候,从客户端得到的数据是iso-8859-1编码的(request.getParameter()得到传递的参数值): 但是我们怎么来改变request的编码呢? 方法有很多种!  比如:在getRequestDispatcher("/jsp/jsptoserv/hello.jsp").f

JAVA里字符编码的探索与理解

编码 今天终于把JAVA里一个比较头痛的问题--字符编码弄清晰了,所以写一篇文章来纪念一下,也为大家提供一点自己的心得. 众所周知,JAVA为了国际通用,用的是UNICODE来保存里面的字符.而UNICODE只是一个种字符集,字符的存储和表示要用到一定的字符编码格式,而与UNICODE对应的字符编码格式就是我们常看到的UTF-8,UTF-16等等,而UTF-8是最常用的,所以人们常常把它和UNICODE等同起来(我以前就是这样的),这在某些情况下是没有错的,但这样的理解在JAVA里就会产生一些混