# **[JAVA] String.getBytes()在不同作業環境下的坑** ###### tags: `Java` `工作筆記` ### 坑點 專案中需要產出指定格式的TXT檔案,介接其他系統的API。 其中規定中文算2碼,英文數字為1碼 原本在本機測試和WinServer測試環境上都是OK的。 結果放上OpenShift環境裡,資料格式直接跑版。 ![Uploading file..._rlzxcsw5u]() ### 原因 **String.getBytes()取用編碼的依序如下:** 1.String.getBytes("指定編碼") 2.JVM設定的編碼 例如:`-Dfile.encoding=UTF-8` 3.系統環境預設的編碼 一般來說 * 中文操作環境下,getBytes()預設使用GBK或CBK2312的編碼 * 英文操作環境下,getBytes()預設使用ISO-8859-1的編碼 而在這些編碼內對中文字byte的長度判別有所不同: ```java= public static void main(String[] args) throws UnsupportedEncodingException { String str = "HELLO! 哈囉"; byte[] defaultByte = str.getBytes(); byte[] GBKByte = str.getBytes("GBK"); byte[] ISOByte = str.getBytes("ISO-8859-1"); byte[] UTF8Byte = str.getBytes("UTF-8"); System.out.println( "作業系統預設Byte長度:"+ defaultByte.length); System.out.println( "GBKByte長度:"+ GBKByte.length); System.out.println( "ISOByte長度:"+ ISOByte.length); System.out.println( "UTF8Byte長度:"+ UTF8Byte.length); } /**在中文環境下的執行結果: 作業系統預設Byte長度:11 GBKByte長度:11 ISOByte長度:9 UTF8Byte長度:13 **/ ``` 以下可以看出每種編碼輸出成txt檔案後的差異。 ```java= public static void main(String[] args) throws UnsupportedEncodingException { byte[] tempMemo1 = new byte[20]; byte[] tempMemo2 = new byte[20]; byte[] tempMemo3 = new byte[20]; byte[] tempMemo4 = new byte[20]; byte[] tempMemo5 = new byte[20]; String memo = "AT哈囉"+ " "; //20個空白 String memo1,memo2,memo3,memo4,memo5; System.arraycopy(memo.getBytes(), 0, tempMemo1, 0, 20); System.arraycopy(memo.getBytes(StandardCharsets.UTF_8), 0, tempMemo2, 0, 20); System.arraycopy(memo.getBytes("BIG5"), 0, tempMemo3, 0, 20); System.arraycopy(memo.getBytes(StandardCharsets.ISO_8859_1), 0, tempMemo4, 0, 20); System.arraycopy(memo.getBytes("GBK"), 0, tempMemo5, 0, 20); memo1 = new String(tempMemo1); System.out.println("預設:"+ memo1.length()); byte2file("D://0DEFAULT.txt", tempMemo1); memo2 = new String(tempMemo2); System.out.println("UTF8:"+ memo2.length()); byte2file("D://0UTF_8.txt", tempMemo2); memo3 = new String(tempMemo3); System.out.println("BIG5:"+ memo3.length()); byte2file("D://0BIG5.txt", tempMemo3); memo4 = new String(tempMemo4); System.out.println("ISO:"+ memo4.length()); byte2file("D://0ISO.txt", tempMemo4); memo5 = new String(tempMemo5); System.out.println("GBK:"+ memo5.length()); byte2file("D://0GBK.txt", tempMemo5); } public static void byte2file(String path,byte[] data) { try { FileOutputStream outputStream =new FileOutputStream(new File(path)); outputStream.write(data); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } } ``` ### 實際範例 :::info 【規格要求】 英文/數字/半形 算 1 碼 中文字/全形 算 2 碼 請提供內容為: 姓名(10碼)+生日(8碼)+地址(40碼)+結尾符號@(1碼) 的txt檔案 ::: 若我要輸出: 姓名:張小明,共計 6 碼,故必須再補齊 4 個半形空白。 生日:19901231,共計 8 碼。 地址:台北市中正區梅花街小飛巷123號,共計 29 碼,故必須再補齊 11 個半形空白。 結尾:@。 txt檔案會長這個樣子: ![Uploading file..._w1ypdn6oy]() ```java= 英文/數字/半形,在程式內基本上不用特殊的處理。 但中文碼/全形的,需要特別注意: // 姓名的處理 byte[] tempName = new byte[10]; name = peopleDTO.getName() + " "; //10個半形空白 System.arraycopy(memo.getBytes("BIG5"), 0, tempMemo, 0, 10); name = new String(tempMemo,"BIG5"); Stringbuilder finalData; finalData.append(name).append(birthday).append(address).append("@"); return return TxtUtil.downloadTxt( FormatUtil.convertDateToString(new Date(), "yyyyMMdd") + ".TXT", finalData.toString()); public final class TxtUtil { public static ResponseEntity<Resource> downloadTxt(String fileName, String txtData) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { // 防止中文亂碼 fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20"); baos.write(txtData.getBytes("BIG5")); ByteArrayResource resource = new ByteArrayResource(baos.toByteArray()); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + fileName) .contentLength(baos.size()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); } } } ``` ### 結論 如果要在各種不同環境下運行,請使用`String.getBytes("指定編碼")`去取得。