輸入字符串與字節數 len,按字節截取前 len 字節,**保證漢字不被截半**(UTF-8 下漢字 3 字節,GBK 下 2 字節)。
byte[] bytes = str.getBytes(charset) 獲取字節數組len >= bytes.length 直接返回原串bytes[len] (即第 len+1 個字節) 是否為 **負值**len 字節屬於多字節字符的**非首字節**(被截半),需 len-- 回退new String(bytes, 0, len, charset) 構造結果
public static String subByBytes(String src, int len, String charset) {
if (src == null) return null;
byte[] bytes = src.getBytes(Charset.forName(charset));
if (len >= bytes.length) return src;
// 回退直到字符邊界
while (len > 0 && bytes[len] < 0) { // 負值表示非首字節
len--;
}
return new String(bytes, 0, len, charset);
}
// 測試
public static void main(String[] args) {
System.out.println(subByBytes("我ABC", 4, "GBK")); // 我AB (漢字2字節)
System.out.println(subByBytes("我ABC漢DEF", 6, "GBK")); // 我ABC (第6字節是漢字首字節,保留)
System.out.println(subByBytes("我ABC", 4, "UTF-8")); // 我A (漢字3字節,第4字節屬於B)
}
byte 有符號,多字節字符的**非首字節**最高位為 1 → 負值。首字節在 UTF-8/GBK 中也可能為負,但「被截半」時第 len 字節必為非首字節 → 負值len 落在中間需回退 2 步)getBytes 與構造時**必須使用相同 Charset**,否則亂碼Java 9+ 可用 String.substring(int beginIndex, int endIndex) 配合 Character.isSupplementaryCodePoint,但仍需自行處理字節邊界。上述工具法通用性最強。