原文出處: 成熟的毛毛蟲的博客html
BASE64 編碼是一種經常使用的字符編碼,在不少地方都會用到。但base64不是安全領域下的加密解密算法。能起到安全做用的效果不好,並且很容易破解,他核心做用應該是傳輸數據的正確性,有些網關或系統只能使用ASCII字符。Base64就是用來將非ASCII字符的數據轉換成ASCII字符的一種方法,並且base64特別適合在http,mime協議下快速傳輸數據。java
在JDK1.6以前,JDK核心類一直沒有Base64的實現類,有人建議用Sun/Oracle JDK裏面的sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder,使用它們的優勢就是不須要依賴第三方類庫,缺點就是可能在將來版本會被刪除(用maven編譯會發出警告),並且性能不佳,後面會有性能測試。git
JDK1.6中添加了另外一個Base64的實現,javax.xml.bind.DatatypeConverter兩個靜態方法parseBase64Binary 和 printBase64Binary,隱藏在javax.xml.bind包下面,不被不少開發者知道。算法
在Java 8在java.util包下面實現了BASE64編解碼API,並且性能不俗,API也簡單易懂,下面展現下這個類的使用例子。apache
java.util.Base64數組
該類提供了一套靜態方法獲取下面三種BASE64編解碼器:安全
1)Basic編碼:是標準的BASE64編碼,用於處理常規的需求app
1
2
3
4
5
6
|
// 編碼
String asB64 = Base64.getEncoder().encodeToString(
"some string"
.getBytes(
"utf-8"
));
System.out.println(asB64);
// 輸出爲: c29tZSBzdHJpbmc=
// 解碼
byte
[] asBytes = Base64.getDecoder().decode(
"c29tZSBzdHJpbmc="
);
System.out.println(
new
String(asBytes,
"utf-8"
));
// 輸出爲: some string
|
2)URL編碼:使用下劃線替換URL裏面的反斜線「/」dom
1
2
3
4
|
String urlEncoded = Base64.getUrlEncoder().encodeToString(
"subjects?abcd"
.getBytes(
"utf-8"
));
System.out.println(
"Using URL Alphabet: "
+ urlEncoded);
// 輸出爲:
Using URL Alphabet: c3ViamVjdHM_YWJjZA==
|
3)MIME編碼:使用基本的字母數字產生BASE64輸出,並且對MIME格式友好:每一行輸出不超過76個字符,並且每行以「\r\n」符結束。jvm
1
2
3
4
5
6
7
|
StringBuilder sb =
new
StringBuilder();
for
(
int
t =
0
; t <
10
; ++t) {
sb.append(UUID.randomUUID().toString());
}
byte
[] toEncode = sb.toString().getBytes(
"utf-8"
);
String mimeEncoded = Base64.getMimeEncoder().encodeToString(toEncode);
System.out.println(mimeEncoded);
|
首先即是經常使用的Apache Commons Codec library裏面的org.apache.commons.codec.binary.Base64;
第二個即是Google Guava庫裏面的com.google.common.io.BaseEncoding.base64() 這個靜態方法;
第三個是net.iharder.Base64,這個jar包就一個類;
最後一個,號稱Base64編碼速度最快的MigBase64,並且是10年前的實現,到如今是否能保持這個稱號,測一測便知道;
上面講了一共7種實現Base64編碼,Jdk裏面3種,第三方實現4種,一旦有選擇,則有必要將他們進行一次高低對比,性能測試是最直接的方式
首先來定義兩個接口
1
2
3
4
5
6
7
8
9
10
|
private
static
interface
Base64Codec
{
public
String encode(
final
byte
[] data);
public
byte
[] decode(
final
String base64)
throws
IOException;
}
private
static
interface
Base64ByteCodec
{
public
byte
[] encodeBytes(
final
byte
[] data);
public
byte
[] decodeBytes(
final
byte
[] base64)
throws
IOException;
}
|
兩個接口區別就是其中一個接口方法參數接收byte數組,返回byte數組,由於byte->byte相比String->byte或者byte->String性能上會快一點,因此區分兩組來測試
1
2
3
4
|
private
static
final
Base64Codec[] m_codecs = {
new
GuavaImpl(),
new
JavaXmlImpl(),
new
Java8Impl(),
new
SunImpl(),
new
ApacheImpl(),
new
MiGBase64Impl(),
new
IHarderImpl() };
private
static
final
Base64ByteCodec[] m_byteCodecs = {
new
ApacheImpl(),
new
Java8Impl(),
new
MiGBase64Impl(),
new
IHarderImpl() };
|
從上面看出,其中支持byte->byte只有4中API;
7個Base64的實現類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
private
static
class
Java8Impl
implements
Base64Codec, Base64ByteCodec
{
private
final
Base64.Decoder m_decoder = Base64.getDecoder();
private
final
Base64.Encoder m_encoder = Base64.getEncoder();
@Override
public
String encode(
byte
[] data) {
return
m_encoder.encodeToString(data);
}
@Override
public
byte
[] decode(String base64)
throws
IOException {
return
m_decoder.decode(base64);
}
public
byte
[] encodeBytes(
byte
[] data) {
return
m_encoder.encode( data );
}
public
byte
[] decodeBytes(
byte
[] base64)
throws
IOException {
return
m_decoder.decode( base64 );
}
}
private
static
class
JavaXmlImpl
implements
Base64Codec
//no byte[] implementation
{
public
String encode(
byte
[] data) {
return
DatatypeConverter.printBase64Binary( data );
}
public
byte
[] decode(String base64)
throws
IOException {
return
DatatypeConverter.parseBase64Binary( base64 );
}
}
..............
|
後面代碼基本就是各類API實現Base64的代碼了,就不詳細列出。
主要測試手段是,生成100M的隨機數,分紅100byte或者1000byte的塊,而後將他們分別編碼和解碼,記錄時間,以下方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
private
static
TestResult testByteCodec(
final
Base64ByteCodec codec,
final
List<
byte
[]> buffers )
throws
IOException {
final
List<
byte
[]> encoded =
new
ArrayList<
byte
[]>( buffers.size() );
final
long
start = System.currentTimeMillis();
for
(
final
byte
[] buf : buffers )
encoded.add( codec.encodeBytes(buf) );
final
long
encodeTime = System.currentTimeMillis() - start;
final
List<
byte
[]> result =
new
ArrayList<
byte
[]>( buffers.size() );
final
long
start2 = System.currentTimeMillis();
for
(
final
byte
[] ar : encoded )
result.add( codec.decodeBytes(ar) );
final
long
decodeTime = System.currentTimeMillis() - start2;
for
(
int
i =
0
; i < buffers.size(); ++i )
{
if
( !Arrays.equals( buffers.get( i ), result.get( i ) ) )
System.out.println(
"Diff at pos = "
+ i );
}
return
new
TestResult( encodeTime /
1000.0
, decodeTime /
1000.0
);
}
|
測試結果
jvm參數:-Xms512m -Xmx4G
一切都很明顯了,從上面看出,sun的表現不是很好,IHarder和MigBase64性能能夠接受,傳說MigBase64性能第一,那也是過去了,在此次測試結果中,新的java8 base64運行速度最好,javaXml表現次之。
若是你須要一個性能好,可靠的Base64編解碼器,不要找JDK外面的了,java8裏面的java.util.Base64以及java6中隱藏很深的javax.xml.bind.DatatypeConverter,他們兩個都是不錯的選擇。
本篇中全部代碼都在http://git.oschina.net/benhail/javase8-sample ,歡迎你們去關注下載