http://blog.csdn.net/l081307114/article/details/46009015
http://www.cnblogs.com/dreammyle/p/5458280.html
. Office2007與Office Open XML
在Office 2007之前,Office一直都是以二進制位的方式存儲,但這種格式不易被其它軟件拿來使用,在各界的壓力下,MicroSoft於2005年發布了基於XML的ooxml開放文檔標准。ooxml的xml schema強調減少load time,增快parsing speed,將child elements分開存儲,而不是multiple attributes一起存,這有點類似於HTML的結構。ooxml 使用XML和ZIP技術結合進行文件存儲,因為XML是一個基於文本的格式,而且ZIP容器支持內容的壓縮,所以其一大優勢就是可以大大減小文件的尺寸。其它特點這里不再敘述。
2. SAX方式解析XML
SAX全稱Simple API for XML,它是一個接口,也是一個軟件包。它是一種XML解析的替代方法,不同於DOM解析XML文檔時把所有內容一次性加載到內存中的方式,它逐行掃描文檔,一邊掃描,一邊解析。所以那些只需要單遍讀取內容的應用程序就可以從SAX解析中受益,這對大型文檔的解析是個巨大優勢。另外,SAX “推" 模型可用於廣播環境,能夠同時注冊多個ContentHandler,並行接收事件,而不是在一個管道中一個接一個地進行處理。一些支持 SAX 的語法分析器包括 Xerces,Apache parser(以前的 IBM 語法分析器)、MSXML(Microsoft 語法分析器)和 XDK(Oracle 語法分析器)。這些語法分析器是最靈活的,因為它們還支持 DOM。
3. POI以SAX解析excel2007文件
所需jar包:poi-3.10-FINAL-20140208.jar,poi-ooxml-3.10-FINAL-20140208.jar, poi-ooxml-schemas-3.10-FINAL-20140208.jar
輔助工具:Open XML SDK 2.5
原始文件:book1.xlsx
SDK展示:注意其中第四行只有三個cell元素,第五行只有兩個cell元素,而這種空單元格的處理正是我們所要注意的
程序源碼:
- package test;
- import java.io.BufferedWriter;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStreamWriter;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import org.apache.poi.openxml4j.opc.OPCPackage;
- import org.apache.poi.ss.usermodel.BuiltinFormats;
- import org.apache.poi.ss.usermodel.DataFormatter;
- import org.apache.poi.xssf.eventusermodel.XSSFReader;
- import org.apache.poi.xssf.model.SharedStringsTable;
- import org.apache.poi.xssf.model.StylesTable;
- import org.apache.poi.xssf.usermodel.XSSFCellStyle;
- import org.apache.poi.xssf.usermodel.XSSFRichTextString;
- import org.xml.sax.Attributes;
- import org.xml.sax.ContentHandler;
- import org.xml.sax.InputSource;
- import org.xml.sax.SAXException;
- import org.xml.sax.XMLReader;
- import org.xml.sax.helpers.DefaultHandler;
- import org.xml.sax.helpers.XMLReaderFactory;
- public class ExampleEventUserModel {
- private static StylesTable stylesTable;
- /**
- * 處理一個sheet
- * @param filename
- * @throws Exception
- */
- public void processOneSheet(String filename) throws Exception {
- OPCPackage pkg = OPCPackage.open(filename);
- XSSFReader r = new XSSFReader( pkg );
- stylesTable = r.getStylesTable();
- SharedStringsTable sst = r.getSharedStringsTable();
- XMLReader parser = fetchSheetParser(sst);
- // Seems to either be rId# or rSheet#
- InputStream sheet2 = r.getSheet("rId1");
- InputSource sheetSource = new InputSource(sheet2);
- parser.parse(sheetSource);
- sheet2.close();
- }
- /**
- * 處理所有sheet
- * @param filename
- * @throws Exception
- */
- public void processAllSheets(String filename) throws Exception {
- OPCPackage pkg = OPCPackage.open(filename);
- XSSFReader r = new XSSFReader( pkg );
- SharedStringsTable sst = r.getSharedStringsTable();
- XMLReader parser = fetchSheetParser(sst);
- Iterator<InputStream> sheets = r.getSheetsData();
- while(sheets.hasNext()) {
- System.out.println("Processing new sheet:\n");
- InputStream sheet = sheets.next();
- InputSource sheetSource = new InputSource(sheet);
- parser.parse(sheetSource);
- sheet.close();
- System.out.println("");
- }
- }
- /**
- * 獲取解析器
- * @param sst
- * @return
- * @throws SAXException
- */
- public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
- XMLReader parser =
- XMLReaderFactory.createXMLReader(
- "org.apache.xerces.parsers.SAXParser"
- );
- ContentHandler handler = new SheetHandler(sst);
- parser.setContentHandler(handler);
- return parser;
- }
- /**
- * 自定義解析處理器
- * See org.xml.sax.helpers.DefaultHandler javadocs
- */
- private static class SheetHandler extends DefaultHandler {
- private SharedStringsTable sst;
- private String lastContents;
- private boolean nextIsString;
- private List<String> rowlist = new ArrayList<String>();
- private int curRow = 0;
- private int curCol = 0;
- //定義前一個元素和當前元素的位置,用來計算其中空的單元格數量,如A6和A8等
- private String preRef = null, ref = null;
- //定義該文檔一行最大的單元格數,用來補全一行最后可能缺失的單元格
- private String maxRef = null;
- private CellDataType nextDataType = CellDataType.SSTINDEX;
- private final DataFormatter formatter = new DataFormatter();
- private short formatIndex;
- private String formatString;
- //用一個enum表示單元格可能的數據類型
- enum CellDataType{
- BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
- }
- private SheetHandler(SharedStringsTable sst) {
- this.sst = sst;
- }
- /**
- * 解析一個element的開始時觸發事件
- */
- public void startElement(String uri, String localName, String name,
- Attributes attributes) throws SAXException {
- // c => cell
- if(name.equals("c")) {
- //前一個單元格的位置
- if(preRef == null){
- preRef = attributes.getValue("r");
- }else{
- preRef = ref;
- }
- //當前單元格的位置
- ref = attributes.getValue("r");
- this.setNextDataType(attributes);
- // Figure out if the value is an index in the SST
- String cellType = attributes.getValue("t");
- if(cellType != null && cellType.equals("s")) {
- nextIsString = true;
- } else {
- nextIsString = false;
- }
- }
- // Clear contents cache
- lastContents = "";
- }
- /**
- * 根據element屬性設置數據類型
- * @param attributes
- */
- public void setNextDataType(Attributes attributes){
- nextDataType = CellDataType.NUMBER;
- formatIndex = -1;
- formatString = null;
- String cellType = attributes.getValue("t");
- String cellStyleStr = attributes.getValue("s");
- if ("b".equals(cellType)){
- nextDataType = CellDataType.BOOL;
- }else if ("e".equals(cellType)){
- nextDataType = CellDataType.ERROR;
- }else if ("inlineStr".equals(cellType)){
- nextDataType = CellDataType.INLINESTR;
- }else if ("s".equals(cellType)){
- nextDataType = CellDataType.SSTINDEX;
- }else if ("str".equals(cellType)){
- nextDataType = CellDataType.FORMULA;
- }
- if (cellStyleStr != null){
- int styleIndex = Integer.parseInt(cellStyleStr);
- XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
- formatIndex = style.getDataFormat();
- formatString = style.getDataFormatString();
- if ("m/d/yy" == formatString){
- nextDataType = CellDataType.DATE;
- //full format is "yyyy-MM-dd hh:mm:ss.SSS";
- formatString = "yyyy-MM-dd";
- }
- if (formatString == null){
- nextDataType = CellDataType.NULL;
- formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
- }
- }
- }
- /**
- * 解析一個element元素結束時觸發事件
- */
- public void endElement(String uri, String localName, String name)
- throws SAXException {
- // Process the last contents as required.
- // Do now, as characters() may be called more than once
- if(nextIsString) {
- int idx = Integer.parseInt(lastContents);
- lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
- nextIsString = false;
- }
- // v => contents of a cell
- // Output after we've seen the string contents
- if (name.equals("v")) {
- String value = this.getDataValue(lastContents.trim(), "");
- //補全單元格之間的空單元格
- if(!ref.equals(preRef)){
- int len = countNullCell(ref, preRef);
- for(int i=0;i<len;i++){
- rowlist.add(curCol, "");
- curCol++;
- }
- }
- rowlist.add(curCol, value);
- curCol++;
- }else {
- //如果標簽名稱為 row,這說明已到行尾,調用 optRows() 方法
- if (name.equals("row")) {
- String value = "";
- //默認第一行為表頭,以該行單元格數目為最大數目
- if(curRow == 0){
- maxRef = ref;
- }
- //補全一行尾部可能缺失的單元格
- if(maxRef != null){
- int len = countNullCell(maxRef, ref);
- for(int i=0;i<=len;i++){
- rowlist.add(curCol, "");
- curCol++;
- }
- }
- //拼接一行的數據
- for(int i=0;i<rowlist.size();i++){
- if(rowlist.get(i).contains(",")){
- value += "\""+rowlist.get(i)+"\",";
- }else{
- value += rowlist.get(i)+",";
- }
- }
- //加換行符
- value += "\n";
- try {
- writer.write(value);
- } catch (IOException e) {
- e.printStackTrace();
- }
- curRow++;
- //一行的末尾重置一些數據
- rowlist.clear();
- curCol = 0;
- preRef = null;
- ref = null;
- }
- }
- }
- /**
- * 根據數據類型獲取數據
- * @param value
- * @param thisStr
- * @return
- */
- public String getDataValue(String value, String thisStr)
- {
- switch (nextDataType)
- {
- //這幾個的順序不能隨便交換,交換了很可能會導致數據錯誤
- case BOOL:
- char first = value.charAt(0);
- thisStr = first == '0' ? "FALSE" : "TRUE";
- break;
- case ERROR:
- thisStr = "\"ERROR:" + value.toString() + '"';
- break;
- case FORMULA:
- thisStr = '"' + value.toString() + '"';
- break;
- case INLINESTR:
- XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
- thisStr = rtsi.toString();
- rtsi = null;
- break;
- case SSTINDEX:
- String sstIndex = value.toString();
- thisStr = value.toString();
- break;
- case NUMBER:
- if (formatString != null){
- thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString).trim();
- }else{
- thisStr = value;
- }
- thisStr = thisStr.replace("_", "").trim();
- break;
- case DATE:
- try{
- thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);
- }catch(NumberFormatException ex){
- thisStr = value.toString();
- }
- thisStr = thisStr.replace(" ", "");
- break;
- default:
- thisStr = "";
- break;
- }
- return thisStr;
- }
- /**
- * 獲取element的文本數據
- */
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- lastContents += new String(ch, start, length);
- }
- /**
- * 計算兩個單元格之間的單元格數目(同一行)
- * @param ref
- * @param preRef
- * @return
- */
- public int countNullCell(String ref, String preRef){
- //excel2007最大行數是1048576,最大列數是16384,最后一列列名是XFD
- String xfd = ref.replaceAll("\\d+", "");
- String xfd_1 = preRef.replaceAll("\\d+", "");
- xfd = fillChar(xfd, 3, '@', true);
- xfd_1 = fillChar(xfd_1, 3, '@', true);
- char[] letter = xfd.toCharArray();
- char[] letter_1 = xfd_1.toCharArray();
- int res = (letter[0]-letter_1[0])*26*26 + (letter[1]-letter_1[1])*26 + (letter[2]-letter_1[2]);
- return res-1;
- }
- /**
- * 字符串的填充
- * @param str
- * @param len
- * @param let
- * @param isPre
- * @return
- */
- String fillChar(String str, int len, char let, boolean isPre){
- int len_1 = str.length();
- if(len_1 <len){
- if(isPre){
- for(int i=0;i<(len-len_1);i++){
- str = let+str;
- }
- }else{
- for(int i=0;i<(len-len_1);i++){
- str = str+let;
- }
- }
- }
- return str;
- }
- }
- static BufferedWriter writer = null;
- public static void main(String[] args) throws Exception {
- ExampleEventUserModel example = new ExampleEventUserModel();
- String str = "Book1";
- String filename = "D:\\"+str+".xlsx ";
- System.out.println("-- 程序開始 --");
- long time_1 = System.currentTimeMillis();
- try{
- writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\"+str+".csv")));
- example.processOneSheet(filename);
- }finally{
- writer.close();
- }
- long time_2 = System.currentTimeMillis();
- System.out.println("-- 程序結束 --");
- System.out.println("-- 耗時 --"+(time_2 - time_1)+"ms");
- }
- }
最后輸出結果:
- 書目,作者,主題,語言,分類,閱讀計划,
- 生活在別處,米蘭.昆德拉,人生感悟,英語,哲理,3周,
- 人間詞話,王國維,詩詞評論,中文,文學,5周,
- 寬容,房龍,,英語,,,
- 深入理解計算機系統,,,,計算機,,
本文實例主要講述了Java生成CSV文件的方法,具體實現步驟如下:
1、新建CSVUtils.java文件:
package com.saicfc.pmpf.internal.manage.utils; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; /** * 文件操作 */ public class CSVUtils { /** * 生成為CVS文件 * * @param exportData 源數據List * @param map csv文件的列表頭map * @param outPutPath 文件路徑 * @param fileName 文件名稱 * @return */ @SuppressWarnings("rawtypes") public static File createCSVFile(List exportData, LinkedHashMap map, String outPutPath, String fileName) { File csvFile = null; BufferedWriter csvFileOutputStream = null; try { File file = new File(outPutPath); if (!file.exists()) { file.mkdir(); } // 定義文件名格式並創建 csvFile = File.createTempFile(fileName, ".csv", new File(outPutPath)); System.out.println("csvFile:" + csvFile); // UTF-8使正確讀取分隔符"," csvFileOutputStream = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(csvFile), "UTF-8"),1024); System.out.println("csvFileOutputStream:" + csvFileOutputStream); // 寫入文件頭部 for (Iterator propertyIterator = map.entrySet().iterator(); propertyIterator.hasNext();) { java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next(); csvFileOutputStream.write( "" + (String) propertyEntry.getValue() != null ? (String) propertyEntry.getValue() : "" + ""); if (propertyIterator.hasNext()) { csvFileOutputStream.write(","); } } csvFileOutputStream.newLine(); // 寫入文件內容 for (Iterator iterator = exportData.iterator(); iterator.hasNext();) { Object row = (Object) iterator.next(); for (Iterator propertyIterator = map.entrySet().iterator(); propertyIterator.hasNext();) { java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next(); csvFileOutputStream.write((String) BeanUtils.getProperty( row, (String) propertyEntry.getKey())); if (propertyIterator.hasNext()) { csvFileOutputStream.write(","); } } if (iterator.hasNext()) { csvFileOutputStream.newLine(); } } csvFileOutputStream.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { csvFileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return csvFile; } /** * 下載文件 * * @param response * @param csvFilePath 文件路徑 * @param fileName 文件名稱 * @throws IOException */ public static void exportFile(HttpServletResponse response, String csvFilePath, String fileName) throws IOException { response.setContentType("application/csv;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); InputStream in = null; try { in = new FileInputStream(csvFilePath); int len = 0; byte[] buffer = new byte[1024]; response.setCharacterEncoding("UTF-8"); OutputStream out = response.getOutputStream(); while ((len = in.read(buffer)) > 0) { out.write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }); out.write(buffer, 0, len); } } catch (FileNotFoundException e) { System.out.println(e); } finally { if (in != null) { try { in.close(); } catch (Exception e) { throw new RuntimeException(e); } } } } /** * 刪除該目錄filePath下的所有文件 * * @param filePath 文件目錄路徑 */ public static void deleteFiles(String filePath) { File file = new File(filePath); if (file.exists()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { files[i].delete(); } } } } /** * 刪除單個文件 * * @param filePath 文件目錄路徑 * @param fileName 文件名稱 */ public static void deleteFile(String filePath, String fileName) { File file = new File(filePath); if (file.exists()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { if (files[i].getName().equals(fileName)) { files[i].delete(); return; } } } } } /** * 測試數據 * * @param args */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) { List exportData = new ArrayList<Map>(); Map row1 = new LinkedHashMap<String, String>(); row1.put("1", "11"); row1.put("2", "12"); row1.put("3", "13"); row1.put("4", "14"); exportData.add(row1); row1 = new LinkedHashMap<String, String>(); row1.put("1", "21"); row1.put("2", "22"); row1.put("3", "23"); row1.put("4", "24"); exportData.add(row1); LinkedHashMap map = new LinkedHashMap(); map.put("1", "第一列"); map.put("2", "第二列"); map.put("3", "第三列"); map.put("4", "第四列"); String path = "c:/export/"; String fileName = "文件導出"; File file = CSVUtils.createCSVFile(exportData, map, path, fileName); String fileName2 = file.getName(); System.out.println("文件名稱:" + fileName2); } }
2、調用createCSVFile方法生成CSV文件
public static void main(String[] args) { String name = "銀行退款數據"; List exportData = new ArrayList(); LinkedHashMap datamMap = null; for (Iterator iterator = refundList.iterator(); iterator.hasNext();) { HashMap map = (HashMap) iterator.next(); datamMap = new LinkedHashMap(); datamMap.put("1", map.get("merOrderId")); datamMap.put("2", DateUtil.convertDateToString("yyyyMMdd", (Date) map.get("orderTime"))); BigDecimal amount = (BigDecimal) map.get("amount"); String amountString = amount.divide(new BigDecimal(10)).toPlainString(); datamMap.put("3", amountString); datamMap.put("4", map.get("remark") != null ? map.get("remark") : ""); exportData.add(datamMap); } LinkedHashMap map = new LinkedHashMap(); map.put("1", "訂單號"); map.put("2", "支付日期"); map.put("3", "退貨現金金額(整數金額 單位:分)"); map.put("4", "退貨原因"); File file = CSVUtils.createCSVFile(exportData, map, filePath, name);// 生成CSV文件 fileName = file.getName(); CSVUtils.exportFile(response, filePath + fileName, fileName);// 下載生成的CSV文件 }
本文轉自:http://www.jb51.net/article/52724.htm