Java 8新特性探究(五)Base64詳解

http://blog.csdn.net/jerome_s/article/details/45285685


BASE64 編碼是一種常用的字符編碼,在很多地方都會用到。但base64不是安全領域下的加密解密算法。能起到安全作用的效果很差,而且很容易破解,他核心作用應該是傳輸數據的正確性,有些網關或系統只能使用ASCII字符。Base64就是用來將非ASCII字符的數據轉換成ASCII字符的一種方法,而且base64特別適合在http,mime協議下快速傳輸數據。

JDK裏面實現Base64的API

在JDK1.6之前,JDK核心類一直沒有Base64的實現類,有人建議用Sun/Oracle JDK裏面的sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder,使用它們的優點就是不需要依賴第三方類庫,缺點就是可能在未來版本會被刪除(用maven編譯會發出警告),而且性能不佳,後面會有性能測試

JDK1.6中添加了另一個Base64的實現,javax.xml.bind.DatatypeConverter兩個靜態方法parseBase64Binary 和 printBase64Binary,隱藏在javax.xml.bind包下面,不被很多開發者知道。

Java 8Java.util包下面實現了BASE64編解碼API,而且性能不俗,API也簡單易懂,下面展示下這個類的使用例子。

java.util.Base64

該類提供了一套靜態方法獲取下面三種BASE64編解碼器:

1)Basic編碼:是標準的BASE64編碼,用於處理常規的需求

?

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裏面的反斜線“/”

?

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”符結束。

?

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);

第三方實現Base64的API

首先便是常用的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年前的實現,到現在是否能保持這個稱號,測一測便知道;

Base64編碼性能測試

上面講了一共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,他們兩個都是不錯的選擇。

from:http://my.oschina.NET/benhaile/blog/267738

還有很多Java8新特性比如:

OOM:Permgen說再見 元空間(MetaSpace)一種新的內存空間誕生

StampedLock將是解決同步問題的新寵

Nashorn :新犀牛 (java8新一代的JavaScript引擎

JavaFX 8新特性

參考:http://my.oschina.net/benhaile/blog?disp=1&catalog=410404&sort=time&p=1 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章