Java 編譯時會依指定或系統預設編碼將原始檔轉為 Unicode 載入記憶體。運行時處理文字檔、網路傳輸、資料庫交互時,編碼轉換更是家常便飯。本文梳理核心原理,並提供一個功能完備的 EncodingToolkit 工具類,涵蓋字串、檔案、輸入流的編碼轉換與讀寫。
String.getBytes(charset))new String(bytes, charset))Java 內部統一使用 UTF-16 (char),所有 I/O 操作需透過 Reader/Writer 或 InputStreamReader/OutputStreamWriter 指定編碼。
// 指定源編碼與目標編碼
public static String reEncoding(String text, String srcEnc, String destEnc)
// 以平台預設編碼讀取字串,轉為目標編碼
public static String reEncoding(String text, String destEnc)
public static boolean reEncoding(File srcFile, String srcEnc,
File destFile, String destEnc)
使用 64KB 字元緩衝區分塊讀寫,適合大檔案。
public static String file2String(File file, String encoding)
public static String stream2String(InputStream in, String encoding)
採用 LineNumberReader 逐行讀取,自動補上系統行分隔符。
public static boolean string2TextFile(String text, File destFile, String encoding)
自動建立父目錄。
package lavasoft.common;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.*;
public class EncodingToolkit {
private static Log log = LogFactory.getLog(EncodingToolkit.class);
public static void main(String[] args) {
String han = "漢";
System.out.println("---------");
}
// 字串轉碼:指定源編碼
public static String reEncoding(String text, String resEncoding, String newEncoding) {
String rs = null;
try {
rs = new String(text.getBytes(resEncoding), newEncoding);
} catch (UnsupportedEncodingException e) {
log.error("不支援的字元編碼: " + resEncoding);
throw new RuntimeException(e);
}
return rs;
}
// 字串轉碼:預設源編碼
public static String reEncoding(String text, String newEncoding) {
String rs = null;
try {
rs = new String(text.getBytes(), newEncoding);
} catch (UnsupportedEncodingException e) {
log.error("不支援的字元編碼: " + newEncoding);
throw new RuntimeException(e);
}
return rs;
}
// 檔案轉碼
public static boolean reEncoding(File resFile, String resEncoding,
File distFile, String newEncoding) {
boolean flag = true;
InputStreamReader reader = null;
OutputStreamWriter writer = null;
try {
reader = new InputStreamReader(new FileInputStream(resFile), resEncoding);
writer = new OutputStreamWriter(new FileOutputStream(distFile), newEncoding);
char[] buf = new char[1024 * 64];
int len;
while ((len = reader.read(buf)) != -1) {
writer.write(buf, 0, len);
}
writer.flush();
} catch (FileNotFoundException e) {
flag = false;
log.error("檔案不存在");
throw new RuntimeException(e);
} catch (IOException e) {
flag = false;
log.error("讀寫異常");
throw new RuntimeException(e);
} finally {
closeQuietly(reader);
closeQuietly(writer);
}
return flag;
}
// 檔案讀為字串
public static String file2String(File resFile, String encoding) {
StringBuffer sb = new StringBuffer();
try {
LineNumberReader reader = new LineNumberReader(
new BufferedReader(new InputStreamReader(new FileInputStream(resFile), encoding)));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append(System.getProperty("line.separator"));
}
reader.close();
} catch (UnsupportedEncodingException e) {
log.error("不支援的編碼: " + encoding);
throw new RuntimeException(e);
} catch (FileNotFoundException e) {
log.error("檔案不存在: " + resFile);
throw new RuntimeException(e);
} catch (IOException e) {
log.error("讀取異常");
throw new RuntimeException(e);
}
return sb.toString();
}
// 輸入流讀為字串
public static String stream2String(InputStream in, String encoding) {
StringBuffer sb = new StringBuffer();
LineNumberReader reader = null;
try {
reader = new LineNumberReader(
new BufferedReader(new InputStreamReader(in, encoding)));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append(System.getProperty("line.separator"));
}
} catch (UnsupportedEncodingException e) {
log.error("不支援的編碼: " + encoding);
throw new RuntimeException(e);
} catch (IOException e) {
log.error("讀取異常");
throw new RuntimeException(e);
} finally {
closeQuietly(reader);
closeQuietly(in);
}
return sb.toString();
}
// 字串寫檔
public static boolean string2TextFile(String text, File distFile, String encoding) {
boolean flag = true;
if (!distFile.getParentFile().exists()) distFile.getParentFile().mkdirs();
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(distFile), encoding);
writer.write(text);
} catch (IOException e) {
flag = false;
log.error("寫入異常");
throw new RuntimeException(e);
} finally {
closeQuietly(writer);
}
return flag;
}
private static void closeQuietly(Closeable c) {
if (c != null) try { c.close(); } catch (IOException ignore) {}
}
}
reEncoding(File, File)),避免 OOM。掌握編碼/解碼原理,配合健壯的工具類,即可從容應對中文亂碼、跨平台部署、舊系統遷移等實戰挑戰。