我今天发现代码里面有个这样的问题,就是POI事件解析Excel的时候,空单元格会被忽略,请问下知道的筒子,这种情况怎么处理,注意是事件读取,附代码 package com.its.fedex.msg.util; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; 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.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import com.its.fedex.msg.exception.ExcelParseException; import com.its.fedex.msg.service.IRowHandler; public class Excel2007Reader extends DefaultHandler { /** * 共享字符串表 */ private SharedStringsTable sst; /** * 上一次的内容 */ private String lastContents; /** * 字符串标识 */ private boolean nextIsString; /** * 工作表索引 */ private int sheetIndex = -1; /** * 行集合 */ private List<String> rowlist = new ArrayList<String>(); /** * 当前行 */ private int curRow = 0; /** * 当前列 */ private int curCol = 0; /** * T元素标识 */ private boolean isTElement; /** * Excel数据逻辑处理 */ private IRowHandler rowHandler; /** * 异常信息,如果为空则表示没有异常 */ private String exceptionMessage; /** * 单元格数据类型,默认为字符串类型 */ private CellDataType nextDataType = CellDataType.SSTINDEX; private final DataFormatter formatter = new DataFormatter(); private short formatIndex; private String formatString; /** * 单元格 */ private StylesTable stylesTable; public void setRowReader(IRowHandler rowHandler) { this.rowHandler = rowHandler; } /** * 遍历工作簿中所有的电子表格 * * @param filename * @throws IOException * @throws OpenXML4JException * @throws SAXException * @throws Exception */ public void process(String filename) throws IOException, OpenXML4JException, SAXException { OPCPackage pkg = OPCPackage.open(filename); XSSFReader xssfReader = new XSSFReader(pkg); stylesTable = xssfReader.getStylesTable(); SharedStringsTable sst = xssfReader.getSharedStringsTable(); XMLReader parser = this.fetchSheetParser(sst); Iterator<InputStream> sheets = xssfReader.getSheetsData(); while (sheets.hasNext()) { curRow = 0; sheetIndex++; InputStream sheet = sheets.next(); InputSource sheetSource = new InputSource(sheet); parser.parse(sheetSource); sheet.close(); } } public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException { XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); this.sst = sst; parser.setContentHandler(this); return parser; } @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { // c => 单元格 if ("c".equals(name)) { // 设定单元格类型 this.setNextDataType(attributes); } // 当元素为t时 if ("t".equals(name)) { isTElement = true; } else { isTElement = false; } // 置空 lastContents = ""; } /** * 单元格中的数据可能的数据类型 */ enum CellDataType { BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL } /** * 处理数据类型 * * @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; formatString = "yyyy-MM-dd hh:mm:ss.SSS"; } if (formatString == null) { nextDataType = CellDataType.NULL; formatString = BuiltinFormats.getBuiltinFormat(formatIndex); } } } /** * 对解析出来的数据进行类型处理 * * @param value * 单元格的值(这时候是一串数字) * @param thisStr * 一个空字符串 * @return */ @SuppressWarnings("deprecation") 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(); try { int idx = Integer.parseInt(sstIndex); XSSFRichTextString rtss = new XSSFRichTextString(sst.getEntryAt(idx)); thisStr = rtss.toString(); rtss = null; } catch (NumberFormatException ex) { 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: thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString); // 对日期字符串作特殊处理 thisStr = thisStr.replace(" ", "T"); break; default: thisStr = " "; break; } return thisStr; } @Override public void endElement(String uri, String localName, String name) throws SAXException { // 根据SST的索引值的到单元格的真正要存储的字符串 // 这时characters()方法可能会被调用多次 if (nextIsString) { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); } // t元素也包含字符串 if (isTElement) { // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符 String value = lastContents.trim(); rowlist.add(curCol, value); curCol++; isTElement = false; } else if ("v".equals(name)) { // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引 String value = this.getDataValue(lastContents.trim(), ""); rowlist.add(curCol, value); curCol++; } else { // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法 if (name.equals("row")) { try { rowHandler.getRows(curRow, rowlist); } catch (ExcelParseException e) { exceptionMessage = e.getMessage(); } rowlist.clear(); curRow++; curCol = 0; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // 得到单元格内容的值 lastContents += new String(ch, start, length); } /** * @return the exceptionMessage */ public String getExceptionMessage() { return exceptionMessage; } } |
|
#1 |
没人知道啊,擦
|
#2 |
100分给我 我告诉你
|
20分
#3 |
private List<Map> parseworkbookVoucher(HSSFWorkbook workbook){ //存放凭证主表 List<Map> VoucherList=new ArrayList<Map>(); int columnNum = 0; Sheet sheet = workbook.getSheetAt(0); if(sheet.getRow(0)!=null){ columnNum = sheet.getRow(0).getLastCellNum()-sheet.getRow(0).getFirstCellNum(); } Row rowkey=sheet.getRow(0); if(columnNum>1){ for (int j = 2; j <= sheet.getLastRowNum(); j++) { Row row=sheet.getRow(j); Map<String, Object> Vouchermap =new HashMap<String, Object>(); for(int i=0;i<columnNum;i++){ Cell cell = row.getCell(i, Row.CREATE_NULL_AS_BLANK); Cell cellkey = rowkey.getCell(i); switch(cell.getCellType()){ case Cell.CELL_TYPE_BLANK: Vouchermap.put(cellkey.getStringCellValue().trim(), ""); break; case Cell.CELL_TYPE_BOOLEAN: Vouchermap.put(cellkey.getStringCellValue().trim(), ""); break; case Cell.CELL_TYPE_NUMERIC: if(DateUtil.isCellDateFormatted(cell)){ //System.out.println("日期:"+cell.getDateCellValue()); Vouchermap.put(cellkey.getStringCellValue().trim(), dateformate(cell.getDateCellValue())); }else{ cell.setCellType(Cell.CELL_TYPE_STRING); //System.out.println("*********"+cellkey.getStringCellValue()); //System.out.println("*********"+cell.getStringCellValue()); //DecimalFormat df = new DecimalFormat("###0.00"); Vouchermap.put(cellkey.getStringCellValue().trim(), cell.getStringCellValue()); } break; case Cell.CELL_TYPE_STRING: Vouchermap.put(cellkey.getStringCellValue().trim(), cell.getStringCellValue()); break; case Cell.CELL_TYPE_ERROR: Vouchermap.put(cellkey.getStringCellValue().trim(), ""); break; } } //Vouchermap.put("Table", "Co_Relationdetails1"); if(null!=Vouchermap.get("cOrgnID")&&!Vouchermap.get("cOrgnID").equals("")){ VoucherList.add(Vouchermap); } } } for (int m = 0; m < VoucherList.size(); m++) { System.out.println(VoucherList.size()); Map map=VoucherList.get(m); System.out.println("模板数据:"+map); } return VoucherList; } 换一个遍历方式,楼主的遍历可能涉及到一些迭代器,其中可能进行了一些处理,具体细节不太了解 |
#4 |
回复楼:
我也很想100分都给你,可是你的做法是基于UserModel解析的,我用的是事件解析,因为数据量比较大,没办法
|
#5 |
楼主能否说下事件解析Excel是什么意思?
基于事件?what? |
#6 |
回复楼:
Event,就是一个先把Excel弄成DOM树的结构,然后用SAX解析,你那种UserModle的解析方式是另外一种常用的方式,但是碰上数据量比较大的情况,就会内存溢出,参看这个博客http://blog.csdn.net/goodkuang2012/article/details/7350985
|
10分
#7 |
单元格是否为空,可以根据
cell.getCellType() == HSSFCell.CELL_TYPE_BLANK 来判断 |
#8 |
回复楼:
没有Cell对象
|
70分
#9 |
poi好久没用了都忘了,应该是有Cell对象的,poi操作的对象不就是sheet row cell 这样的
|
#10 |
回复楼:
那是前面说的UserModel的解析方式,那种方式的确有,操作简便,就是很容易内存溢出
|
#11 |
昨天自己解决了,结贴
attributes.getValue(“r”); |
#12 |
attributes.getValue(“r”); 在什么地方判断啊? 我也遇到空格的问题了
|
#13 |
请问,这个问题怎么解决啊
|
#14 |
这个能读excel中的“真空”值吗?
|
#15 |
回复11楼: 怎么解决的? |
#16 |
回复15楼: 我已解决,有问题问我 |
#17 |
DefaultHandle接口里面仔细找下,有一个方法就可以满足你。加油,另外03頒的也支持时间驱动。
|
#18 |
回复15楼: 请问这个空单元格问题是怎么解决的啊 |
#19 |
attributes.getValue(“r”);
nmb 装 解决就说 孩子啊哪里装nmb 楼主wcnm |
#20 |
刚才我调试了一下,attributes.getValue(“r”);是获取单元格的坐标例如A1,B1,D1,把这些跟读取出来的数值绑定一下,哪个没绑定就给他设为一个控制就行了,哈哈
|
#21 |
@wujiangqing123
具体如何处理,是否可以的供一下代吗 |