UTF-8的CSV文件用Excel打开会出现乱码

原因:

输出的CSV文件中没有BOM

 

什么是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编码了。

 

 

 

解决方案:

 

1、Excel通过“数据”->“来自文本文件”打开csv文件后,设置文件编码为utf-8

2、改变编码为UTF-16LE,添加\uFEFF

 

参照代码:

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
/**
 * 将数据导出到指定格式文件的工具类.
 * @author arenzhj
 *
 */
public class DataExportFileUtil{
	//CSV config
	public static final String CSV_FILE = ".csv";	
	public static final String CSV_TYPE = "text/plain";
	public static final String CSV_ENCODING = "UTF-16LE";
	public static final String CSV_BOMENCODING = "\uFEFF";
	//Excel config	
	public static final String EXCEL_TYPE = "application/vnd.ms-excel";
	public static final String EXCEL_FILE = ".xls"; 
	public static final String EXCEL_ENCODING = "UTF-8";
	//Excel Styles
	public static final String STYLE_HEADER = "HEADER";
	public static final String STYLE_BORDER = "BORDER";
	public static final String STYLE_DATECELL = "DATECELL";
	public static final String STYLE_NUMBERCELL = "NUMBERCELL";
	
	public static final String ENTER = "\r\n"; 
	
	/**
	 * 导出csv文件
	 * @param fileName
	 * @param rowMapper
	 * @param modelMaps
	 * @param response
	 * @throws Exception
	 */
	public static void exportDataCSVFile(String fileName, 
			LinkedHashMap rowMapper,
			List<Map<String, String>> modelMaps,
			HttpServletResponse response) {
		ServletOutputStream out =null;
		BufferedOutputStream buff =null;
		try {
			out = response.getOutputStream();
			buff = new BufferedOutputStream(out); 
			StringBuffer write = new StringBuffer();
			// 写入文件头部  
	        for (Iterator propertyIterator = rowMapper.entrySet().iterator(); propertyIterator.hasNext();) {  
	            java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator  
	                    .next();  
	            write.append("\""  
	                    + propertyEntry.getValue().toString() + "\"");  
	            if (propertyIterator.hasNext()) {  
	            	write.append(",");  
	            }  
	        }  
	        write.append(ENTER);  
			// 写入文件内容  
			for (Iterator iterator = modelMaps.iterator(); iterator.hasNext();) {    
			    
				Map<String, String> modelMap =(Map<String, String>)iterator.next();
			    for (Iterator propertyIterator = rowMapper.entrySet().iterator(); propertyIterator.hasNext();) {    
			        java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();    
			        write.append("\""    
			                +  modelMap.get(propertyEntry.getKey()) 
			                + "\"");    
			        if (propertyIterator.hasNext()) {    
			        	write.append(",");    
			            }    
			       }    
			        if (iterator.hasNext()) {
			        	write.append(ENTER); 
			        }    
			}
	      //输出Excel文件.
			response.setContentType(CSV_TYPE+";charset="+CSV_ENCODING);
			//中文文件名支持
			String encodedfileName = new String(fileName.getBytes(CSV_ENCODING), CSV_ENCODING);
			response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedfileName +CSV_FILE + "\"");
			buff.write((CSV_BOMENCODING+write.toString()).getBytes(CSV_ENCODING)); 
			buff.flush();  
			buff.close(); 
		} catch (IOException e) { 
			e.printStackTrace();
		}finally {  
			try {  
				buff.close();  
				out.close();  
			} catch (Exception e) {  
				e.printStackTrace();  
			}  
		}   
	} 
	
	/**
	 * 导出Excel(含多个Sheet)
	 * @param fileName 导出Excel文件名称
	 * @param sheetNames 导出Excel的Sheet名
	 * @param rowMappers 各Excel数据标题
	 * @param modelMaps 各Excel数据集
	 * @param response 
	 * @throws Exception
	 */
	public static void exportDataExcelFile(String fileName,
			LinkedHashMap sheetNames,
			Map<String,LinkedHashMap> rowMappers,
			Map<String,List<Map<String, String>>> modelMaps,
			HttpServletResponse response)throws Exception{
		HSSFWorkbook workbook = new HSSFWorkbook();
		//创建所有Cell Style
		Map<String, HSSFCellStyle> styles = createStyles(workbook);
		int sheetNum=0;
		for (Iterator sheetNameIterator = sheetNames.entrySet().iterator(); sheetNameIterator.hasNext();) {  
            Entry sheetNameEntry = (Entry) sheetNameIterator.next();
            HSSFSheet sheet = workbook.createSheet();
            workbook.setSheetName(sheetNum, sheetNameEntry.getValue().toString(),HSSFWorkbook.ENCODING_UTF_16);
            LinkedHashMap rowMapper =rowMappers.get(sheetNameEntry.getKey());
            HSSFRow row;
            int rowIndex = 0;
            short colIndex = 0; 
            row=sheet.createRow(rowIndex); 
            // 写入文件头部  
            for (Iterator headerIterator = rowMapper.entrySet().iterator(); headerIterator.hasNext();) {  
                Entry headerEntry = (Entry) headerIterator.next();
                
                HSSFCell cell = row.createCell(colIndex++);
        		cell.setEncoding(HSSFCell.ENCODING_UTF_16);
        		cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        		cell.setCellValue(headerEntry.getValue().toString());
        		cell.setCellStyle(styles.get(STYLE_HEADER)); // 设置该cell浮点数的显示格式
        		colIndex++;
            }  
            rowIndex++; 
            // 写入内容部分
            List<Map<String, String>> models=modelMaps.get(sheetNameEntry.getKey());
    		if(!models.isEmpty()){
    			 for (Map<String, String> modelMap : models) {
				 	row=sheet.createRow(rowIndex);
				 	colIndex = 0; 
				 	 for (Iterator headerIterator = rowMapper.entrySet().iterator(); headerIterator.hasNext();) {  
						Entry headerEntry = (Entry) headerIterator.next();
						
						HSSFCell cell = row.createCell(colIndex++);
						cell.setEncoding(HSSFCell.ENCODING_UTF_16);
						cell.setCellType(HSSFCell.CELL_TYPE_STRING);
						cell.setCellValue(modelMap.get(headerEntry.getKey()));
						cell.setCellStyle(styles.get(STYLE_BORDER)); // 设置该cell浮点数的显示格式
						colIndex++;
				 	 }  
		            rowIndex++; 
    			 }
    		} 
            sheetNum++;
		}
		//输出excel文件
	    responseExcel(response,workbook,fileName); 
	} 
	
	
	
	private static Map<String, HSSFCellStyle> createStyles(HSSFWorkbook wb) {
		Map<String, HSSFCellStyle> styles = new HashMap<String, HSSFCellStyle>();
		//普通字体
		HSSFFont normalFont = wb.createFont();
		normalFont.setFontHeightInPoints((short) 10);
		//加粗字体
		HSSFFont boldFont = wb.createFont();
		boldFont.setFontHeightInPoints((short) 10);
		boldFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		//蓝色加粗字体
		HSSFFont blueBoldFont = wb.createFont();
		blueBoldFont.setFontHeightInPoints((short) 10);
		blueBoldFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		blueBoldFont.setColor(HSSFColor.BLUE.index);
		
		//行标题格式
		HSSFCellStyle headerStyle = wb.createCellStyle();
		headerStyle.setFont(boldFont);
		headerStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		HSSFPalette palette = ((HSSFWorkbook) wb).getCustomPalette();  
		palette.setColorAtIndex((short)9, (byte) (0xff & 200), (byte) (0xff & 200), (byte) (0xff & 200));
		headerStyle.setFillForegroundColor((short)9);
		headerStyle.setAlignment(headerStyle.ALIGN_CENTER);
		headerStyle.setVerticalAlignment(headerStyle.VERTICAL_CENTER);
		setBorder(headerStyle);
		styles.put(STYLE_HEADER, headerStyle);
		
		//border
		HSSFCellStyle borderCellStyle = wb.createCellStyle();
		setBorder(borderCellStyle);
		styles.put(STYLE_BORDER, borderCellStyle);
				
		HSSFDataFormat df = wb.createDataFormat();
		//日期格式
		HSSFCellStyle dateCellStyle = wb.createCellStyle();
		dateCellStyle.setFont(normalFont);
		dateCellStyle.setDataFormat(df.getFormat("yyyy-MM-dd HH:mm:ss"));
		setBorder(dateCellStyle);
		styles.put(STYLE_DATECELL, dateCellStyle);
		
		//数字格式
		HSSFCellStyle numberCellStyle = wb.createCellStyle();
		numberCellStyle.setFont(normalFont);
		numberCellStyle.setDataFormat(df.getFormat("#,##0.00"));
		setBorder(numberCellStyle);
		styles.put(STYLE_NUMBERCELL, numberCellStyle);

		return styles;
	}
	
	private static void setBorder(HSSFCellStyle style) {
		//设置边框
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setRightBorderColor(HSSFColor.BLACK.index);

		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setLeftBorderColor(HSSFColor.BLACK.index);

		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style.setTopBorderColor(HSSFColor.BLACK.index);

		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBottomBorderColor(HSSFColor.BLACK.index);
	}
	
	
	
	public static void responseExcel(HttpServletResponse response,
			HSSFWorkbook workbook ,String fileName) throws Exception {
		//输出Excel文件.
		response.setContentType(EXCEL_TYPE+";charset="+EXCEL_ENCODING);
		//中文文件名支持
		String encodedfileName = new String(fileName.getBytes(EXCEL_ENCODING), EXCEL_ENCODING);
		
		response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedfileName +EXCEL_FILE + "\"");
		workbook.write(response.getOutputStream());
		response.getOutputStream().flush();
	}
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值