背景
我在項目中使用阿裡雲OSS存儲檔案,導出時導出為csv格式的檔案。然而打開時總是存在中文亂碼。
通過網上的一番搜尋,大抵是使用記事本先打開csv檔案,然後再儲存為ANSI格式,然後再用excel打開時就不存在亂碼了。但這不是程式裡的解決方式,我們不可能提供一個半成品的導出檔案供使用者使用。經過一番網上搜尋,發現問題的根源在于UTF8的BOM資訊頭。
本來UTF8是不需要BOM頭的,這就不得不說到微軟的可惡了。
BOM簡介
BOM中文譯作”位元組順序标記”,UTF8本不需要BOM來表明位元組順序,但WINDOWS用BOM來标記檔案檔案的編碼方式。BOM的UTF8編碼是”EF BB BF”,是以如果接收者收到以”EF BB BF”開頭的位元組流,就知道這是UTF8編碼了。WINDOWS系軟體儲存的UTF8編碼的檔案需要檔案的開頭保有這個BOM字元。
問題解決
項目中使用OSS存儲檔案,存儲成功後傳回一個簽名過的檔案url位址,前端再根據這個url去請求擷取檔案。由于前端是直接使用”window.open(url)”的方式,直接新開視窗通路連結,下載下傳下來的檔案預設是UTF8編碼的,是以使用excel打開時需要BOM字元來表明是UTF8編碼,否則其中的中文則會産生亂碼。
是以,在OSS存儲時,我們就需要額外添加BOM頭一并存儲。代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17OSSClient client = new OSSClient(ossHelper.getEndPoint(), ossHelper.getAccessKeyId(),
ossHelper.getAccessKeySecret());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType("application/vnd.ms-excel");
objectMetadata.setContentEncoding("UTF-8");
objectMetadata.setContentDisposition("attachment; filename=" + fileName + ".csv");
// 增加BOM頭資訊
String bom = new String(new byte[] { (byte) 0xEF, (byte) 0xBB,(byte) 0xBF });
try {
// 以同樣的編碼擷取位元組流
client.putObject(ossHelper.getBucketName(), fileName,
new ByteArrayInputStream((bom + exportFileString).getBytes("UTF-8")), objectMetadata);
}catch (UnsupportedEncodingException e){
e.printStackTrace();
}