這篇文章適合有一定編碼基礎的人看,純手動解決亂碼問題請參見:
轉碼保存后,重新打開即可。
轉碼操作如下:
編輯器->另存為->ASCII碼格式文件/UTF-8含BOM格式->保存。
參考文章:https://blog.csdn.net/m0_37125796/article/details/73928157
我寫了一個CSV文件的數據列表,用Excel打開之后發現全部亂碼了,這讓我很尷尬。
於是找到了上面這篇文章,參照他的方式,進行了一些修改,終於解決了這個問題。
解決辦法:給CSV文件添加BOM頭
什么是BOM?
簡單來說,它是一個可以證明內容以什么編碼格式存在的中間人。
Excel是ASCII碼格式文件,而CSV文件是UTF-8格式。如果不進行兼容,這兩種不同格式肯定沒法正常展示的。
所以,我需要對UTF-8編碼的CSV文件寫入一個UTF-8的BOM頭,告訴Excel“我是UTF-8編碼的,你要按照我的編碼格式來解析。”這樣,Excel才能真正認清文件里的內容。
上面的參考文章給出的解決方案如下:
OutputStreamWriter osw = new OutputStreamWriter(resp.getOutputStream(), "UTF-8");
// 要輸出的內容
result = (String)contentMap.get(RESPONSE_RESULT);
resp.setHeader("Content-Disposition", "attachment;filename=test.csv");
osw.write(new String(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF }));
osw.write(result);
osw.flush();
我興高采烈地依葫蘆畫瓢,把我的代碼成他那樣,而且在我的mac電腦上已經運行成功了,Excel可以正常打開我的CSV文件。
於是,我興高采烈地交貨了,把我的成品發給了老大,讓他檢閱。
誰知,老大給我的答案是:“打開都是亂碼。”
“怎么可能,我在我電腦上能打開啊!”我下意識地反駁了一句,后來想想好傻啊,難不成是老大騙我嗎,還不趕緊去檢查代碼!
我帶着疑問,老大也過來幫我看哪里出了問題,先上一段我修改前的代碼:
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write(new String(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }));
osw.write(s);
osw.flush();
我按照參考的文章寫了這代碼,看起來好像沒什么問題。但是老大看出了貓膩,他把文件以16進制格式打開,發現我的BOM頭是EF BB 3F
,而我寫入的BOM是EF BB BF
。為何有這樣的差異,我的BF怎么變成3F了?
因為只有EF BB BF
才能表示UTF-8,所以差一個字母都不行。
老大懷疑問題出在osw.write(new String(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }));
上,String默認是UTF-16的編碼,而我們寫入時應該不帶任何格式,才能讓解析器讀懂,如果被String這么一轉,轉成其他格式,這就不好說了。
不愧是老大,一語中的!
於是,我嘗試把String去掉,直接寫入byte數組的BOM。修改之后的代碼如下:
FileOutputStream fos = new FileOutputStream(file);
fos.write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF });
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.append(s);
osw.flush();
原來的osw.write()
也改成了osw.append()
。(這個不改也無礙)
最終運行結果是可喜的,可以成功打開。
其實我們兩個電腦之間的差異,一個是windows,一個是mac。我懷疑是mac對BOM做了兼容,檢查沒有windows嚴格。后面我一查,其實UTF-8本身沒有BOM,給它加上BOM純屬是微軟的習慣。