首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 編碼問題徹底解決指南:GBK、UTF-8、UTF-16BE 實測與最佳實踐

     編輯:Java 相關知識

前言

亂碼是 Java 開發者的噩夢。本文從位元組層面實測三種常見編碼差異,建立「編碼必須對應」的鐵律,並給出生產環境完整解決方案。

實驗環境與程式碼

Eclipse 專案預設編碼 GBK,測試字串 "我愛ABC"(中英混合)。

public class Demo1 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "我愛ABC";
        
        // GBK:中文 2 bytes,英文 1 byte
        printBytes("GBK", s.getBytes("gbk"));
        
        // UTF-8:中文 3 bytes,英文 1 byte
        printBytes("UTF-8", s.getBytes("utf-8"));
        
        // UTF-16BE:中英文皆 2 bytes(大端序)
        printBytes("UTF-16BE", s.getBytes("utf-16be"));
        
        // 錯誤示範:以專案預設 GBK 解碼 UTF-16BE 位元組 → 亂碼
        String wrong = new String(s.getBytes("utf-16be")); 
        System.out.println("錯誤解碼:" + wrong);
        
        // 正確:指定對應編碼
        String right = new String(s.getBytes("utf-16be"), "utf-16be");
        System.out.println("正確解碼:" + right);
    }
    static void printBytes(String label, byte[] bytes) {
        System.out.print(label + ": ");
        for (byte b : bytes) System.out.printf("%02X ", b & 0xFF);
        System.out.println();
    }
}

實測輸出與分析

GBK:       CE D2 C3 C7 41 42 43   // "我愛" 各 2 bytes,ABC 各 1 byte
UTF-8:     E6 88 91 E6 84 9B 41 42 43  // "我愛" 各 3 bytes
UTF-16BE:  62 11 61 1B 00 41 00 42 00 43  // 所有字元固定 2 bytes
編碼中文英文/數字適用場景
GBK/GB180302 bytes1 byte中文 Windows 系統、舊專案相容
UTF-83 bytes1 byteWeb 標準、國際化、資料庫、檔案傳輸首選
UTF-16BE/LE2 bytes2 bytesJava 內部 char 型別、特定協定

亂碼產生的三大根因

  1. 編碼/解碼不一致:寫入用 UTF-8,讀取用 GBK(或反向)
  2. 隱式預設編碼:new String(bytes)、FileReader、System.out.println 依賴 file.encoding,跨平台部署極易出錯
  3. 多層傳遞未指定:HTTP 請求/回應、JDBC 連線、檔案 IO、日誌框架各層編碼未對齊

生產環境完整解決方案

1. 源頭統一:專案、檔案、資料庫全 UTF-8

  • IDE / 建構工具:-Dfile.encoding=UTF-8、Maven <properties><project.build.sourceEncoding>UTF-8</...>
  • 資料庫:CREATE DATABASE ... CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;,連線 URL 加 ?characterEncoding=utf8
  • HTML 頁面:<meta charset="UTF-8">

2. 程式碼層:顯式指定、拒絕隱式

// 讀寫檔案
try (Reader r = new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8);
     Writer w = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8)) { ... }

// HTTP Servlet
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");

// JDBC
url = "jdbc:mysql://host/db?characterEncoding=utf8&useSSL=false&serverTimezone=UTC";

3. 框架層:一次設定、全域生效

  • Spring Boot:spring.http.encoding.charset=UTF-8、spring.http.encoding.force=true
  • Tomcat server.xml:<Connector URIEncoding="UTF-8" ... />
  • Logback/Log4j2:<charset>UTF-8</charset>

4. 除錯利器:十六進位檢視

// 線上排查:印出原始 bytes 判斷實際編碼
byte[] raw = ...;
for (byte b : raw) System.out.printf("%02X ", b & 0xFF);
// 對照碼表確認編碼,再決定正確解碼方式

總結

編碼問題本質是位元組序列與字元映射表的對應關係。只要堅持「全鏈路顯式指定 UTF-8」,99% 亂碼問題消失。遇到存量非 UTF-8 系統,邊界處統一轉碼(讀入即轉 UTF-8,寫出再轉目標編碼),內部統一用 Unicode (String) 處理,是架構層面的終極解法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved