`

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();
	}
	
}

 

分享到:
评论

相关推荐

    Java避免UTF-8的csv文件打开中文出现乱码的方法

    Java避免UTF-8的csv文件打开中文出现...Java避免UTF-8的csv文件打开中文出现乱码的方法是使用UTF-16LE编码格式,并在文件头部输出BOM。同时,需要考虑Excel版本的兼容性问题,以确保csv文件可以正确地被打开和读取。

    bat脚本将csv格式UTF-8批量转ANSI

    描述中提到的情况是用户在尝试用Excel打开UTF-8编码的CSV文件时遇到了中文乱码。这是因为Excel默认可能不支持或识别UTF-8编码,尤其是不带BOM(Byte Order Mark)的UTF-8文件。解决这个问题的方法是将这些文件转换为...

    PLSQL导出CSV后中文乱码解决办法

    5. **加载数据**:确认编码设置无误后,点击“加载”按钮,Excel将使用UTF-8编码解析CSV文件,此时中文字符应该能正常显示。 除了以上方法,你还可以尝试其他解决方案,例如在PLSQL Developer工具中直接设置导出时...

    java读写csv文件,中文乱码问题

    - 文件流操作时忘记指定编码,会导致默认编码(通常是平台默认编码,如Windows的GBK)被使用,从而出现乱码。 - 读写操作时,确保编码一致,避免在转换过程中引入乱码。 6. **工具有助于调试**: - 使用文本编辑...

    Python利用 utf-8-sig 编码格式解决写入 csv 文件乱码问题

    但是,当使用 `utf-8` 编码写入 CSV 文件时,如果文件开头没有 BOM (Byte Order Mark) 标记,那么 Excel 在打开文件时可能会出现乱码。这是因为 Excel 默认会根据 BOM 来判断文件的编码格式。 ```python import ...

    解决方案_EXCEL打开Tableau导出数据存在中文乱码情况的解决方案

    如果CSV文件的编码方式为utf-8或Unicode等,EXCEL打开时就会出现中文乱码的情况。 解决这个问题的方法是使用记事本打开CSV文件,然后点击菜单:“文件-另存为”,选择ANSI编码方式,最后保存完毕后,用EXCEL打开这...

    Oracle导出成csv格式后显示乱码的解决方法

    Oracle数据库可能使用的是UTF-8或其他编码,而默认的文本编辑器或Excel可能使用不同的编码。因此,当编码不匹配时,就会出现乱码。 2. **使用记事本打开并重新保存**: 第一步是使用记事本打开CSV文件。记事本是一...

    解决Arcgis10.2.2中dbf文件用EXCEL打开乱码问题.zip

    在ArcGIS 10.2.2版本中,用户可能会遇到一个常见的问题:当尝试用Microsoft Excel打开与ArcGIS相关的dbf文件时,数据可能会显示为乱码。这个问题主要涉及到字符编码的不匹配,下面我们将详细探讨这个问题的原因、...

    EXCEL用VBA程序用ADO读取CSV

    在Excel VBA编程中,有时我们需要处理大量的数据,这时候可以借助外部数据访问对象(ADO)来读取和操作数据,比如CSV(逗号分隔值)文件。CSV格式因其通用性和简洁性,常用于数据交换。下面我们将详细介绍如何使用...

    Vtiger-5.2.1-导出数据文件Excel及CSV中文乱码问题完美修正包

    如果导出文件的编码与系统或软件默认的编码不一致,就会出现乱码现象。Vtiger 5.2.1可能默认使用了一种不支持中文的编码,导致导出的Excel和CSV文件无法正确显示中文内容。 修正这个问题通常涉及以下几个步骤: 1....

    爬虫csv乱码1

    当一个UTF-8编码的CSV文件被Excel尝试以ANSI编码方式打开时,由于编码不匹配,Excel无法正确解析非ASCII字符,从而导致乱码的出现。 解决这个问题的方法是转换CSV文件的编码方式,使其与Excel的编码方式保持一致。...

    php导出csv文件无乱码示例

    然而,由于编码问题,有时在导出CSV文件时会出现乱码。本示例将详细讲解如何使用PHP正确地导出CSV文件,避免出现乱码情况,并介绍相关的关键知识点。 首先,我们需要了解字符编码的基本概念。在处理文本数据时,...

    excel转csv转vcf和vcf转csv转excel

    1,所有字段如在中文,一定要以汉字开头,否则不能转为utf-8编码。 2,如转换后出现乱码,请将excel表格中的内容加上边框表格。 vcf转csv转excel步骤: 导出手机vcf文件 - VCF2CSV读取vcf转为csv表格 - 打开excel\...

    bootstrap table导出表格支持中文csv、pdf、txt等

    在导出时,需要确保文件以UTF-8编码保存。 在实际应用中,你可以通过调整Bootstrap Table的配置和插件设置,以及确保整个数据流的编码一致性,来实现中文表格数据的顺利导出。如果遇到问题,可以查阅相关插件的文档...

    Excel出现乱码怎么办?.docx

    * 使用正确的文件编码:在保存文件时,选择正确的编码格式,例如UTF-8或GBK。 * 使用记事本打开文件:在打开文件前,使用记事本打开文件,可以避免乱码的问题。 * 使用Excel的字符集设置:在Excel中,设置正确的字符...

    Navicat for MySql 导入EXCEL中文乱码问题解决

    在使用Navicat for MySQL工具进行数据导入时,经常会出现中文乱码的问题,尤其是在处理Excel文件时更为常见。这种现象不仅影响数据的正确性,还可能导致后续的数据分析和处理出现错误。因此,有效地解决Navicat for ...

    java生成csv文件乱码的解决方法示例 java导出csv乱码

    - `readCsv`方法简单地使用`Files.readFirstLine`从文件中读取第一行,同样使用UTF-8编码。 - 这个方法适用于简单的读取操作,如果需要读取整个文件,可能需要使用更复杂的方法,例如逐行迭代文件。 5. **测试...

    GeoLite2-City-CSV_20200324.zip

    里面有ipv4和ipv6地址,经纬度,城市,定位。GeoLite_-City_Locations-zh-CN.csv是ansi编码,可以用excel直接打开,GeoLite2-City-Locations-zh-CN.csv是utf-8编码,打开乱码。

    [最新知识]excel打开是乱码怎么办.doc

    解决方法是使用文本编辑器(如记事本)打开CSV文件,将其另存为TXT文件,确保选择正确的编码(如UTF-8),然后再用Excel打开这个新保存的TXT文件,这样通常能显示正确的汉字。 其次,如果Excel文件本身损坏导致乱码...

    CSV拆分工具.exe

    这里特别提到,拆分后的CSV文件不应以UTF-8格式保存,因为这可能导致中文字符出现乱码。通常,CSV文件默认采用ANSI(Windows-1252)编码,如果原始文件是用这种编码保存的,拆分后也应保持相同编码,以确保中文字符...

Global site tag (gtag.js) - Google Analytics