有幾個因素在起作用:
- 文本文件沒有用於描述其編碼的固有元數據(對於所有關於尖括號稅的討論,都有XML是流行的)
- Windows的默認編碼仍然是一個8位(或雙字節)「ANSI」性格與價值觀的有限範圍內設置 - 寫在這個格式的文本文件是無法移植
- 要從講一個Unicode文件ANSI文件,Windows應用程序依賴文件開頭處的byte order mark(not strictly true - Raymond Chen explains)。理論上,BOM是告訴你數據的endianess(字節順序)。對於UTF-8,即使只有一個字節順序,Windows應用程序依靠標記字節自動發現它是Unicode(儘管您會注意到記事本在其打開/保存對話框中有一個編碼選項)。
- 說Java因爲不自動寫入UTF-8 BOM而中斷,這是錯誤的。例如,在Unix系統上,將BOM寫入腳本文件是錯誤的,許多Unix系統使用UTF-8作爲默認編碼。有些時候,你不希望它在Windows上,或者說,當你將數據附加到現有的文件,如:
fos = new FileOutputStream(FileName,Append);
這裏是UTF-8的數據可靠地附加到文件的方法:
private static void writeUtf8ToFile(File file, boolean append, String data)
throws IOException {
boolean skipBOM = append && file.isFile() && (file.length() > 0);
Closer res = new Closer();
try {
OutputStream out = res.using(new FileOutputStream(file, append));
Writer writer = res.using(new OutputStreamWriter(out, Charset
.forName("UTF-8")));
if (!skipBOM) {
writer.write('\uFEFF');
}
writer.write(data);
} finally {
res.close();
}
}
用法:
public static void main(String[] args) throws IOException {
String chinese = "\u4E0A\u6D77";
boolean append = true;
writeUtf8ToFile(new File("chinese.txt"), append, chinese);
}
注:如果文件已經存在,你選擇了追加和現有的數據不是 UTF-8編碼,唯一的代碼w ^虐待創造是一團糟。
下面是在這段代碼中使用的Closer
類型:
public class Closer implements Closeable {
private Closeable closeable;
public <T extends Closeable> T using(T t) {
closeable = t;
return t;
}
@Override public void close() throws IOException {
if (closeable != null) {
closeable.close();
}
}
}
此代碼如何基於字節順序標記讀取文件中的Windows風格的最好的猜測:
private static final Charset[] UTF_ENCODINGS = { Charset.forName("UTF-8"),
Charset.forName("UTF-16LE"), Charset.forName("UTF-16BE") };
private static Charset getEncoding(InputStream in) throws IOException {
charsetLoop: for (Charset encodings : UTF_ENCODINGS) {
byte[] bom = "\uFEFF".getBytes(encodings);
in.mark(bom.length);
for (byte b : bom) {
if ((0xFF & b) != in.read()) {
in.reset();
continue charsetLoop;
}
}
return encodings;
}
return Charset.defaultCharset();
}
private static String readText(File file) throws IOException {
Closer res = new Closer();
try {
InputStream in = res.using(new FileInputStream(file));
InputStream bin = res.using(new BufferedInputStream(in));
Reader reader = res.using(new InputStreamReader(bin, getEncoding(bin)));
StringBuilder out = new StringBuilder();
for (int ch = reader.read(); ch != -1; ch = reader.read())
out.append((char) ch);
return out.toString();
} finally {
res.close();
}
}
用法:
public static void main(String[] args) throws IOException {
System.out.println(readText(new File("chinese.txt")));
}
(System.out使用默認編碼,所以無論它是否打印任何東西ble取決於你的平臺和configuration。)
可能重複[什麼是字符編碼,爲什麼我應該打擾它](http://stackoverflow.com/questions/10611455/what-is-character-encoding-and - 爲什麼我應該打擾它) – Raedwald 2015-04-10 12:35:24