Java 讀取csv文件后,再保存到磁盤上,然后直接用Excel打開,你會發現里面都是亂碼。
貼上代碼:
public class Test { public static void main(String[] args) { try { File file = new File("c://csv//aa.csv"); FileOutputStream out = new FileOutputStream(file); out.write(IOUtils.toByteArray(Test.class.getResourceAsStream("/template.csv"))); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
原因:讀取的文件字節流中缺失了BOM,Excel發現沒有BOM,則不會用UTF-8編碼打開文件(有人說用acsii碼打開),造成亂碼。
解決方案就是在文件字節流起始處加上UTF-8的BOM,代碼如下:public class Test {
public static void main(String[] args) { byte commonCsvHead[] = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; try { File file = new File("c://csv//aa.csv"); FileOutputStream out = new FileOutputStream(file); out.write( Bytes.concat(commonCsvHead, IOUtils .toByteArray(Test.class.getResourceAsStream("/template.csv")))); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
什么是BOM?
BOM —— Byte Order Mark,中文名譯作“字節順序標記”。在這里找到一段關於 BOM 的說明: 在UCS 編碼中有一個叫做 "Zero Width No-Break Space" ,中文譯名作“零寬無間斷間隔”的字符,它的編碼是 FEFF。而 FFFE 在 UCS 中是不存在的字符,所以不應該出現在實際傳輸中。UCS 規范建議我們在傳輸字節流前,先傳輸字符 "Zero Width No-Break Space"。這樣如果接收者收到 FEFF,就表明這個字節流是 Big-Endian 的;如果收到FFFE,就表明這個字節流是 Little- Endian 的。因此字符 "Zero Width No-Break Space" (“零寬無間斷間隔”)又被稱作 BOM。 UTF-8 不需要 BOM 來表明字節順序,但可以用 BOM 來表明編碼方式。字符 "Zero Width No-Break Space" 的 UTF-8 編碼是 EF BB BF。所以如果接收者收到以 EF BB BF 開頭的字節流,就知道這是 UTF-8編碼了。Windows 就是使用 BOM 來標記文本文件的編碼方式的。 字符U+FEFF如果出現在字節流的開頭,則用來標識該字節流的字節序,是高位在前還是低位在前。如果它出現在字節流的中間,則表達零寬度非換行空格的意義,用戶看起來就是一個空格。從Unicode3.2開始,U+FEFF只能出現在字節流的開頭,只能用於標識字節序,就如它的名稱——字節序標記——所表示的一樣;除此以外的用法已被舍棄。取而代之的是,使用U+2060來表達零寬度無斷空白。 類似WINDOWS自帶的記事本等軟件,在保存一個以UTF-8編碼的文件時,會在文件開始的地方插入三個不可見的字符(0xEF 0xBB 0xBF,即BOM)。它是一串隱藏的字符,用於讓記事本等編輯器識別這個文件是否以UTF-8編碼。對於一般的文件,這樣並不會產生什么麻煩。但對於 PHP來說,BOM是個大麻煩。 PHP並不會忽略BOM,所以在讀取、包含或者引用這些文件時,會把BOM作為該文件開頭正文的一部分。根據嵌入式語言的特點,這串字符將被直接執行(顯示)出來。由此造成即使頁面的 top padding 設置為0,也無法讓整個網頁緊貼瀏覽器頂部,因為在html一開頭有這3個字符呢!
不同編碼的字節順序標記(BOM)表示:
編碼
|
表示 (
十六進制)
|
表示 (
十進制)
|
---|---|---|
EF BB BF
|
239 187 191
|
|
UTF-16(大端序)
|
FE FF
|
254 255
|
UTF-16(小端序)
|
FF FE
|
255 254
|
UTF-32(大端序)
|
00 00 FE FF
|
0 0 254 255
|
UTF-32(小端序)
|
FF FE 00 00
|
255 254 0 0
|
2B 2F 76和以下的
一個字節:[ 38 | 39 | 2B | 2F ]
|
43 47 118和以下的
一個字節:[ 56 | 57 | 43 | 47 ]
|
|
en:UTF-1
|
F7 64 4C
|
247 100 76
|
en:UTF-EBCDIC
|
DD 73 66 73
|
221 115 102 115
|
en:Standard Compression Scheme for Unicode
|
0E FE FF
|
14 254 255
|
en:BOCU-1
|
FB EE 28
及可能跟隨着FF
|
251 238 40
及可能跟隨着255
|
GB-18030
|
84 31 95 33
|
132 49 149 51
|