用java代碼解決excel打開csv文件亂碼問題


 

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

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM