2023年11月28日发(作者:)

Excel打开csv格式⽂件中⽂乱码的解决

【乱码解决】

接到⼀个需求,需要将PC管理端页⾯的Excel⽂件下载改为CSV的格式。据说CSV也是⼀种⽐较通⽤的做法,因为Excel

各个版本对于单Sheet的⾏数都会有限制,⼤数据量的情况下直接⽤CSV会⽅便很多,另外如果使⽤Excel组装数据,那么接

⼝实现的内存也会占⽤更多(更多的对象)。

直接上代码:

package CSVUtil;

import 5987StringUtils;

import ter;

import ctView;

import rvletRequest;

import rvletResponse;

import StreamWriter;

import rdCharsets;

import ;

import ;

public class CsvView extends AbstractView {

public static final String TEMPLATE_KEY = "templateName";

public static final String OUTPUT_NAME_KEY = "output";

public static final Integer LIMIT_RAW = 15000;

/**

* Subclasses must implement this method to actually render the view.

*

The first step will be preparing the request: In the JSP case,

* this would mean setting model objects as request attributes.

* The second step will be the actual rendering of the view,

* for example including the JSP via a RequestDispatcher.

*

* @param model combined output Map (never {@code null}),

* with dynamic values taking precedence over static attributes

* @param request current HTTP request

* @param response current HTTP response

* @throws Exception if rendering failed

*/

@Override

protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

List entryList = (List) (TEMPLATE_KEY);

String fileName = (String) (OUTPUT_NAME_KEY);

String rfc5987FileName = 5987_encode(fileName);

tentType("application/octet-stream");

der("Content-Disposition", "attachment;filename="" + rfc5987FileName + "";filename*=utf-8''" + rfc5987FileName);

OutputStreamWriter outputStreamWriter = new OutputStreamWriter(putStream(),

_8);

CSVWriter writer = new CSVWriter(outputStreamWriter);

for (int i = 0; i < (); i++) {

String[] strings = (i);

ext(strings);

}

();

}

}

Controller层:

@Controller

@RequestMapping(value = "/manage/order")

@Api(value = "", tags = "订单")

public class ChargeOrderController {

@DubboReference

CsvView view = new CsvView();

String time = new SimpleDateFormat("yyyy-MM-dd").format(new Date());

ribute(TE_KEY, dataList);

ribute(_NAME_KEY, ("订单-%", time));

return view;

}

}

测试也能够正常下载CSV⽂件的,但是⽤Excel打开这个⽂件发现中⽂乱码,明明设置了UTF-8的怎么会乱码呢?再次

尝试⽤记事本打开⽂件发现,中⽂是可以正常显⽰的。此时对⽂本另存为UTF8格式,再次⽤Excel打开,此时中⽂能够正常

显⽰了。

⽹上搜索⼀番找到了原因。csv⽂件前必须要加个BOM头,Excel才能正确打开⽂件。于是做如下修改:

...

List entryList = (List) (TEMPLATE_KEY);

String fileName = (String) (OUTPUT_NAME_KEY);

String rfc5987FileName = 5987_encode(fileName);

tentType("application/octet-stream");

der("Content-Disposition", "attachment;filename="" + rfc5987FileName + "";filename*=utf-8''" + rfc5987FileName);

OutputStreamWriter outputStreamWriter = new OutputStreamWriter(putStream(),

_8);

byte[] bom = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};

(new String(bom));

CSVWriter writer = new CSVWriter(outputStreamWriter);

for (int i = 0; i < (); i++) {

String[] strings = (i);

ext(strings);

}

();

...

此时下载的csv⽂件使⽤excel能够正常打开,且中⽂显⽰正常。

————————————————————————————————————————————————

BOM是什么】

BOM的全称是Byte Order Mark,字节顺序标记。它是⼀种特殊的Unicode字符,作为⼀个魔数⼀样的存在,可以告诉正

在读取这个⽂本流的程序三件事情:

1.16位或者32位编码的情况下,⽂本流的字节顺序;

2.⼀个⽐较⾼级别的确认信息,表明这个⽂本流的格式是Unicode

3.使⽤了Unicode字符编码。

但是这个BOM信息,⽤不⽤都是可选的,有些软件⽀持,有些软件不⽀持。在Windows环境下,很多软件都是⽀持,甚

⾄要求这个BOM信息的;但是UNIX环境下,如果携带了BOM信息,很多时候⼜会出问题。所以,这⾥要注意的是,到底使

⽤这个流的软件是否⽀持BOM,到了Windows环境下,如果出现了乱码,要能想到这个问题点;⽽在Linux环境下,或者是

跨平台的软件,如果出现了问题,⼜要排除这个点。

有些软件对于BOM的设置是可选的,⽐如Intellij Idea中对于配置⽂件的设置,就可以选择;Notepad++中也是可以选

的。是否选择,完全看我们的需求,但是使⽤不当也会带来上述问题。

另外,要注意的是,Windows处理⽂本时,会⾃动加上这个BOM信息。⽐如,新建⼀个⽂本,另存为的时候,选择

UTF-8格式,保存⽂件,此时可以看到⽂本的⼤⼩变成了3字节,这个3字节就是被加上了BOM信息。