Java技術 | 細談 Java 8 中的 Base64


簡要了解

Base 64是一種使64個字符來表示任意二進制數據的方法。Base 64是一種非常常用的二進制編解碼方案。

有些說法是說,使用Base 64作為加密解密的功能,比如一個Web系統中,密碼字段存入數據庫的時候使用Base64.encode一下,其實Base 64的編碼、解碼方法都是簡單公開的,用以加密、解密實在談不上啥保障性。

在Java 8中,整合了Base 64。Java 8 為開發者提供了 java.util.Base64 的工具類,Java 8現在有內置編碼器和解碼器的Base 64編碼。在Java 8中有三種類型的Base 64編碼。

第一種,簡單Base 64

Basic 編碼是標准的Base 64編碼,用於處理常規的需求:輸出的內容不添加換行符,而且輸出的內容由64個基本字符組成。

輸出映射設置字符在A-ZA-Z0-9+/。編碼器不添加任何換行輸出和解碼器拒絕在A-Za-z0-9+/以外的任何字符。

第二種,URL編碼

輸出映射設置字符在A-Za-z0-9-_。輸出URL和文件名安全。由於標准的Basic編碼可能會出現+ / ,在URL中就不能直接作為參數,所以又有一種“url safe” 的Base 64編碼,其實就是吧字符 +/分別變成-_
在這里插入圖片描述

第三種,MIME編碼

輸出映射到MIME友好的格式。輸出表示在每次不超過76個字符行和使用'\r'后跟一個換行符'\n'回車作為行分隔符。無行隔板的存在是為了使編碼的結束輸出。MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型。是設定某種擴展名的文件用對應的應用程序來打開的方式類型。

它是一種互聯網標准,擴展了電子郵件標准,使其可以支持:非ASCII字符文本;非文本格式附件(二進制、聲音、圖像等);由多部分組成的消息體;包含非ASCII字符的頭信息等。

舉個栗子:右鍵中有一個Word附件(二進制文件),點擊預覽,瀏覽器會直接打開Office。可以理解為MIME設定了這種對應關系。

MIME編碼器會使用基本的字母數字產生Base 64輸出,而且對MIME格式友好:每一行輸出不超過76個字符,而且每行以“\r\n”符結束。

實用API與代碼示例

API

Base 64類

序號 方法 描述
1 Base64.getEncoder() 返回一個 Base64.Encoder ,編碼使用基本型 base64 編碼方案
2 Base64.getDecoder() 返回一個 Base64.Decoder ,解碼使用基本型 base64 編碼方案
3 Base64. getUrlEncoder() 返回一個 Base64.Encoder ,編碼使用 URL 和文件名安全型 base64 編碼方案
4 Base64.getUrlDecoder() 返回一個 Base64.Decoder ,解碼使用 URL 和文件名安全型 base64 編碼方案。
5 Base64.getMimeEncoder() 返回一個 Base64.Encoder ,編碼使用 MIME 型 base64 編碼方案。
6 Base64.getMimeEncoder(int lineLength, byte[] lineSeparator) 返回一個 Base64.Encoder ,編碼使用 MIME 型 base64 編碼方案,可以通過參數指定每行的長度及行的分隔符。
7 Base64.getMimeDecoder() 返回一個 Base64.Decoder ,解碼使用 MIME 型 base64 編碼方案。

內嵌類Encoder

序號 方法名 描述
1 byte[] encode(byte[] src) 編碼,返回一個byte數組
2 int encode(byte[] src, byte[] dst) 編碼,寫進新的byte數組
3 String encodeToString(byte[] src) 編碼,返回一個字符串
4 ByteBuffer encode(ByteBuffer buffer) 編碼
5 OutputStream wrap(OutputStream os) 編碼
6 Encoder withoutPadding() 編碼

內嵌類Decoder

序號 方法名 描述
1 byte[] decode(byte[] src) 解碼,返回一個byte數組,入參為byte數組
2 byte[] decode(String src) 解碼,返回一個byte數組,入參為字符串
3 int decode(byte[] src, byte[] dst) 解碼
4 ByteBuffer decode(ByteBuffer buffer) 解碼
5 InputStream wrap(InputStream is) 解碼

代碼示例

package com.kjgym.common.java8;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author kjgym
 * @description Demo for Java8's Base64
 * @date 2019/9/17 11:25
 */
public class Java8Base642 {

    public static void main(String[] args) {
        final String demoStr = "kjgym";
        final byte[] strByte = demoStr.getBytes(StandardCharsets.UTF_8);

        // 基本型編碼方案
        String s = Base64.getEncoder().encodeToString(strByte);
        System.out.println("基本編碼: " + s);
        String ss = new String(Base64.getDecoder().decode(s));
        System.out.println("解碼: " + ss);

        // 使用 URL 和文件名安全型 base64 編碼方案。
        String s1 = Base64.getEncoder().encodeToString(strByte);
        System.out.println("URL編碼: " + s1);
        String ss1 = new String(Base64.getUrlDecoder().decode(s));
        System.out.println("解碼: " + ss1);

        // 使用 MIME 型 base64 編碼方案
        String s2 = Base64.getMimeEncoder().encodeToString(strByte);
        System.out.println("MIME編碼: " + s2);
        String ss2 = new String(Base64.getMimeDecoder().decode(s));
        System.out.println("解碼: " + ss2);

    }
}

結果:

基本編碼: a2pneW0=
解碼: kjgym
URL編碼: a2pneW0=
解碼: kjgym
MIME編碼: a2pneW0=
解碼: kjgym

閱讀源碼

  1. 先來總體看一下Base 類,該類主要包含兩個內嵌類EncoderDecoder以及七個構造內嵌類的方法:

在這里插入圖片描述

  1. 再看兩個內嵌類。比如Encoder(部分源代碼):

    public static class Encoder {
    
            private final byte[] newline;
            private final int linemax;
            private final boolean isURL;
            private final boolean doPadding;
    
            private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding {
                this.isURL = isURL;
                this.newline = newline;
                this.linemax = linemax;
                this.doPadding = doPadding;
            }
     
            static final Encoder RFC4648 = new Encoder(false, null, -1, true);
            static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
            static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
    
            public byte[] encode(byte[] src) {}
    
            public int encode(byte[] src, byte[] dst) {}
    
            @SuppressWarnings("deprecation")
            public String encodeToString(byte[] src) {}
    
            public ByteBuffer encode(ByteBuffer buffer) {}
    
            public OutputStream wrap(OutputStream os) {}
    
            public Encoder withoutPadding() {}
    
            private int encode0(byte[] src, int off, int end, byte[] dst) {}
        }
    

    構造器私有化,對外提供單個靜態對象,然后在Base 64類中,使用getEncoder的方式愛調用,使用了單例模式。

    static final Encoder RFC4648 = new Encoder(false, null, -1, true);
    static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
    static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
    
  2. Decoder與上文Encoder相似,這里不再贅述。有興趣自己Ctrl + 單擊去看源碼。

拓展

  1. StandardCharsets類。在java.nio.charset包下的一個類,在字符串和byte數組相互轉換需要制定編碼的時候使用。該類有六種編碼格式:

    /*
     * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    package java.nio.charset;
    
    /**
     * Constant definitions for the standard {@link Charset Charsets}. These
     * charsets are guaranteed to be available on every implementation of the Java
     * platform.
     *
     * @see <a href="Charset#standard">Standard Charsets</a>
     * @since 1.7
     */
    public final class StandardCharsets {
    
        private StandardCharsets() {
            throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
        }
        /**
         * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
         * Unicode character set
         */
        public static final Charset US_ASCII = Charset.forName("US-ASCII");
        /**
         * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
         */
        public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
        /**
         * Eight-bit UCS Transformation Format
         */
        public static final Charset UTF_8 = Charset.forName("UTF-8");
        /**
         * Sixteen-bit UCS Transformation Format, big-endian byte order
         */
        public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
        /**
         * Sixteen-bit UCS Transformation Format, little-endian byte order
         */
        public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
        /**
         * Sixteen-bit UCS Transformation Format, byte order identified by an
         * optional byte-order mark
         */
        public static final Charset UTF_16 = Charset.forName("UTF-16");
    }
    
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM