精华内容
下载资源
问答
  • <pre><code>// Read your Excel workbook try { $inputFileType = PHPExcel_IOFactory::identify($target_file); $objReader = PHPExcel_IOFactory::createReader($inputFileType); $objPHPExcel = $objReader-&...
  • Java 解析复杂表格excel

    2020-11-26 16:02:37
    在实际开发中,上传excel文件是十分常见问题,一般情况下,解析的思路无非1. 固定表头进行解析;2. 每一行进行解析。但是偶尔会碰一下一些格式比较复杂的表格,用以上方式解析就 得不到我们想要结果了。 例如...

    解析复杂表格

    在实际开发中,上传excel文件是十分常见的问题,一般情况下,解析的思路无非1. 固定表头进行解析;2. 每一行进行解析。但是偶尔会碰一下一些格式比较复杂的表格,用以上方式解析就 得不到我们想要的结果了。
    例如以下这张表,乍一看是不是有种心态崩溃的感觉,
    在这里插入图片描述
    面对这种复杂表格,就需要采取特殊的方式了,首先,还是将思路,实现放到最后再说;1.按照每一行去解析,但是在解析时,需要判断是否为单元格;2. 得到数据后,还需要根据行号进行过滤,然后对每一行单元格数据进行合并操作;3. 得到数据后,最后需要根据列号进行过滤,对每一列单元格进行合并操作。

    实现

    话不多说,上代码:

    1. 判断是否为单元格:
    /**
    	 *
    	 *
    	 * @param sheet
    	 *            表单
    	 * @param cellRow
    	 *            被判断的单元格的行号
    	 * @param cellCol
    	 *            被判断的单元格的列号
    	 * @return row: 行数;col列数
    	 * @throws IOException
    	 * @Author zhangxinmin
    	 */
    	private static Map<String, Integer> getMergerCellRegionRow(Sheet sheet, int cellRow,
    											  int cellCol) {
    		Map<String, Integer> map = new HashMap<>();
    		int retVal = 0, retCol= 0 ;
    		int sheetMergerCount = sheet.getNumMergedRegions();
    		for (int i = 0; i < sheetMergerCount; i++) {
    			CellRangeAddress cra = (CellRangeAddress) sheet.getMergedRegion(i);
    			int firstRow = cra.getFirstRow(); // 合并单元格CELL起始行
    			int firstCol = cra.getFirstColumn(); // 合并单元格CELL起始列
    			int lastRow = cra.getLastRow(); // 合并单元格CELL结束行
    			int lastCol = cra.getLastColumn(); // 合并单元格CELL结束列
    			if (cellRow >= firstRow && cellRow <= lastRow) { // 判断该单元格是否是在合并单元格中
    				if (cellCol >= firstCol && cellCol <= lastCol) {
    					retVal = lastRow - firstRow + 1; // 得到合并的行数
    					retCol = lastCol - firstCol + 1; // 得到合并的列数
    					break;
    				}
    			}
    		}
    		map.put("row", retVal);
    		map.put("col", retCol);
    		return map;
    	}
    
    private static Integer isMergedRegion(Sheet sheet,int row ,int column) {
    		int sheetMergeCount = sheet.getNumMergedRegions();
    		for (int i = 0; i < sheetMergeCount; i++) {
    			CellRangeAddress range = sheet.getMergedRegion(i);
    			int firstColumn = range.getFirstColumn();
    			int lastColumn = range.getLastColumn();
    			int firstRow = range.getFirstRow();
    			int lastRow = range.getLastRow();
    			if(row >= firstRow && row <= lastRow){
    				if(column >= firstColumn && column <= lastColumn){
    					return i;
    				}
    			}
    		}
    		return -1;
    	}
    
    1. 解析代码:
    public static List<CellRowAndColDTO> readDiffDataBySheet(Sheet sheet, int startRows){
    		List<CellRowAndColDTO> result = new ArrayList<>();
    		for (int rowIndex = startRows, z = sheet.getLastRowNum(); rowIndex <= z; rowIndex++) {
    			Row row = sheet.getRow(rowIndex);
    			if (row == null) {
    				continue;
    			}
    
    			int rowSize = row.getLastCellNum();
    			for (int columnIndex = 0; columnIndex < rowSize; columnIndex++) {
    				CellRowAndColDTO dto = new CellRowAndColDTO();
    				Cell cell = row.getCell(columnIndex);
    				if (cell != null){
    					// 读取单元格数据格式(标记为字符串)
    					cell.setCellType(CellType.STRING);
    					String value = cell.getStringCellValue();
    					if(0 != isMergedRegion(sheet, rowIndex,columnIndex)){//判断是否合并格
    						// 处理有值的cell
    //						if (StringUtils.isEmpty(value)) {
    //							continue;
    //						}
    						dto.setRow(rowIndex);
    						dto.setCol(columnIndex);
    						Map<String, Integer> map = getMergerCellRegionRow(sheet, rowIndex, columnIndex);//获取合并的行列
    						dto.setCellCol(map.get("col") == 0? 1:map.get("col"));
    						dto.setCellRow(map.get("row") == 0? 1:map.get("row"));
    						dto.setCellValue(value);
    						result.add(dto);
    
    					}else{
    						dto.setRow(rowIndex);
    						dto.setCol(columnIndex);
    						Map<String, Integer> map = getMergerCellRegionRow(sheet, rowIndex, columnIndex);//获取合并的行列
    						dto.setCellCol(1);
    						dto.setCellRow(1);
    						dto.setCellValue(value);
    						result.add(dto);
    					}
    
    				}
    			}
    		}
    		List<CellRowAndColDTO> dtos = new ArrayList<>();
    		Map<Integer, List<CellRowAndColDTO>> map = result.stream().collect(Collectors.groupingBy(CellRowAndColDTO::getRow));//根据行进行分组
    		map.forEach((k,v) -> {
    			for(int i =0;i<v.size();i++){
    				if(i!=0){
    					Integer col = dtos.get(dtos.size()-1).getCol()+dtos.get(dtos.size()-1).getCellCol();
    					if(v.get(i).getCol() == col){
    						dtos.add(v.get(i));
    						continue;
    					}
    				}else{
    					dtos.add(v.get(i));
    				}
    
    			}
    		});
    
    		List<CellRowAndColDTO> dtos2 = new ArrayList<>();
    		Map<Integer, List<CellRowAndColDTO>> map2 = dtos.stream().collect(Collectors.groupingBy(CellRowAndColDTO::getCol));//根据列分组
    		map2.forEach((k,v) -> {
    			for(int i =0;i<v.size();i++){
    				if(i!=0){
    					if(v.get(i).getCellRow() != 1){
    						if(v.get(i).getCellCol() == v.get(i-1).getCellCol() && v.get(i).getCellRow() == v.get(i-1).getCellRow()){
    							if(v.get(i).getCellRow() == 1 && v.get(i).getCellCol() == 1){
    								dtos2.add(v.get(i));
    								continue;
    							}else{
    								if(StringUtils.isBlank((v.get(i).getCellValue()))){
    									continue;
    								}
    							}
    						}
    					}
    
    				}
    				dtos2.add(v.get(i));
    			}
    		});
    		return dtos2;
    	}
    

    说明一下: 首先我先获取每一行,然后对该行的每一个单元格cell对象进行判断处理,判断时候为单元格,如果是,则将行号,列号,合并行数,合并列数,数值进行存储,存储到List集合;然后,对该集合进行过滤操作,通过java8 stream流的方式先根据行号进行分组,然后获取下一个格的位置col ,然后进行判断,如果是下一个格则进行存储;如果是该单元格内的空格,则跳出循环。然后再根据列进行分组,根据行号列号进行对合并格其他空格单元格进行过滤,最后完成数据库存储,完成解析操作。

    普通表格按行解析

    public static List<String[]> readData(String fileType, int startRows, boolean ignoreRowBlank, InputStream is) throws IOException {
    		List<String[]> result = new ArrayList<>();
    
    		Workbook wb = readWorkBook(fileType, is);
    		for (int sheetIndex = 0; sheetIndex < wb.getNumberOfSheets(); sheetIndex++) {
    			Sheet sheet = wb.getSheetAt(sheetIndex);
    
    			for (int rowIndex = startRows, z = sheet.getLastRowNum(); rowIndex <= z; rowIndex++) {
    				Row row = sheet.getRow(rowIndex);
    				if (row == null) {
    					continue;
    				}
    
    				int rowSize = row.getLastCellNum();
    				String[] values = new String[rowSize];
    				boolean hasValue = false;
    				for (int columnIndex = 0; columnIndex < rowSize; columnIndex++) {
    					String value = "";
    					Cell cell = row.getCell(columnIndex);
    					if (cell != null) {
    						// 注意:一定要设成这个,否则可能会出现乱码,后面版本默认设置
    						switch (cell.getCellType()) {
    							case HSSFCell.CELL_TYPE_STRING:
    								value = cell.getStringCellValue();
    								break;
    							case HSSFCell.CELL_TYPE_NUMERIC:
    								if (HSSFDateUtil.isCellDateFormatted(cell)) {
    									Date date = cell.getDateCellValue();
    									if (date != null) {
    										value = new SimpleDateFormat("yyyy-MM-dd")
    												.format(date);
    									} else {
    										value = "";
    									}
    								} else {
    									//value = new DecimalFormat("0").format(cell.getNumericCellValue());
    									if (HSSFDateUtil.isCellDateFormatted(cell)) {
    										value = String.valueOf(cell.getDateCellValue());
    									} else {
    										cell.setCellType(Cell.CELL_TYPE_STRING);
    										String temp = cell.getStringCellValue();
    										// 判断是否包含小数点,如果不含小数点,则以字符串读取,如果含小数点,则转换为Double类型的字符串
    										if (temp.indexOf(".") > -1) {
    											value = String.valueOf(new Double(temp)).trim();
    										} else {
    											value = temp.trim();
    										}
    									}
    								}
    								break;
    							case HSSFCell.CELL_TYPE_FORMULA:
    								// 导入时如果为公式生成的数据则无值
    								if (!cell.getStringCellValue().equals("")) {
    									value = cell.getStringCellValue();
    								} else {
    									value = cell.getNumericCellValue() + "";
    								}
    								break;
    							case HSSFCell.CELL_TYPE_BLANK:
    								break;
    							case HSSFCell.CELL_TYPE_ERROR:
    								value = "";
    								break;
    							case HSSFCell.CELL_TYPE_BOOLEAN:
    								value = (cell.getBooleanCellValue() == true ? "Y"
    
    										: "N");
    								break;
    							default:
    								value = "";
    						}
    					}
    					values[columnIndex] = value;
    					if (!value.isEmpty()) {
    						hasValue = true;
    					}
    				}
    				if (!ignoreRowBlank || hasValue) {//不为忽略空行模式或不为空行
    					result.add(values);
    				}
    			}
    		}
    		return result;
    	}
    

    这里我就不过多叙述这个按行解析了,代码思路比较简单一看就能懂。

    总结

    该文章为我总结平时开发过程中解决的难题的经验和思路;如果有更好的解决办法希望能不吝赐教。大家携手在开发的道路上越走越远。不喜勿喷。

    展开全文
  • 博主称这类excel模板为略复杂表头模板(蓝色部分为表头部分,蓝色前面几行是博主项目的基础样式,称为元数据),这类excel的表头多为2-3行,甚至于5/6行 ,具有合并层级关系,看似复杂,但只需要在我们以前的基础上...

    我们在第三篇文章中谈到了那些非常反人类的excel模板,博主为了养家糊口,也玩命做出了相应的解析方法...

     

    我们先来看看第一类复杂表头:

     

    ......

    博主称这类excel模板为略复杂表头模板(蓝色部分为表头部分,蓝色前面几行是博主项目的基础样式,称为元数据),这类excel的表头多为2-3行,甚至于5/6行 ,具有合并层级关系,看似复杂,但只需要在我们以前的基础上稍微做一下重构就可以完美实现解析。

     

    我们以各地区户籍人口城乡构成表头为例:

    其实,只要我们能准确解析这类表头所表达的意思,就能复用以前的代码做解析工作

    也就是说,重点在于表头解析方法GetExcelHeaders(),

    我们返回看第三篇文章http://www.cnblogs.com/csqb-511612371/p/4891492.html中这个方法的代码:

    第17行到33行

     1                    for (int j = headerRow.FirstCellNum; j < cellCount; j++)
     2                     {
     3                         if (!string.IsNullOrEmpty(headerRow.GetCell(j).StringCellValue.Trim()))
     4                         {
     5                             // 根据 键-值 是否已存在做不同处理
     6                             try
     7                             {
     8                                 string oldValue = dict[j];
     9                                 dict.Remove(j);
    10                                 dict.Add(j, oldValue + headerRow.GetCell(j).StringCellValue.Trim());
    11                             }
    12                             catch (Exception)
    13                             {
    14                                 dict.Add(j, headerRow.GetCell(j).StringCellValue.Trim());
    15                             }
    16                         }
    17                     }

    我们在这儿做了一个列的循环,对表头所在行每一列做了一个值合并,那么我们可以预料:这个表头解析出来的结果:

    0,地区

    1,总人口(年末)(万人)

    2,城镇人口人口数

    3,比重(%)

    4,乡村人口人口数

    5,#比重(%)

    那么我们的xml配置文件就该写成这样:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <module>
     3   <add firstHeaderRow="5"                lastHeaderRow="7"/>
     4   <add headerText="年份"                 propertyName="Year"                               dataType="System.Int32"/>
     5   <add headerText="总人口(年末)(万人)"   propertyName="TotalAmount"                        dataType="System.double"/>
     6   <add headerText="城镇人口人口数"       propertyName="UrbanPermanentPopulation"           dataType="System.double"/>
     7   <add headerText="比重(%)"              propertyName="UrbanPermanentPopulationShare" dataType="System.double"/>
     8   <add headerText="乡村人口人口数"       propertyName="RuralPermanentPopulation"           dataType="System.double"/>
     9   <add headerText="#比重(%)"              propertyName="RuralPermanentPopulationShare" dataType="System.double"/>
    10 </module>

    注:

    1.第三行:5-7代表模板表头所在位置

     

    OK,我们这样做就解析出了这个含有合并单元格的表头,那么接下来的所有流程就和简单表头一样了。

    我们来总结一下:

    1.修改配置文件xml,按我们的解析规则做映射配置

    2.重构表头解析方法,按我们的配置解析表头数据

     

    我们再来看看更复杂的表头模板:

     

    ......

    这类模板除了表头外,还含有左表头。当然左表头也是需要存入数据库的,只是需要我们能准确解析到合并单元格所表达内容,方便导出是还原excel数据样式

    以第一个excel水文特征值为例:

    1.表头按合并表头做xml配置

    2.左表头深色部分为合并区域,浅色部分为弱区域,可扩充

    3.左表头需要解析成

    水位.潮汐性质    

    水位.历年最高潮位

    水位.多年平均高潮位

    ...

    好吧,那么我们这次需要重构的就是解析数据的方法GetExcelDatas,我们看看第三篇文章:

    http://www.cnblogs.com/csqb-511612371/p/4891492.html中的代码

    我们看到第42-45行,对空值只做了简单处理,那么我们先来普及一下NPOI遇到合并单元格怎么取值?

    NPOI只能取到合并单元格最左上角单元格的值,其它单元格均为空值。那么既然我们的数据中含有左表头含有合并单元格,这个空值就需要做一个复杂判断了

    我们先来捋一捋思路:如果取值时遇到空值,可能是单元格本就是空值,也可能是该单元格是合并单元格,切不在合并坐标左上角...

    OK,我们来看重构后的这一段代码

     1                      if (value == "")
     2                     {
     3                         int firstRegionRow = 0;
     4                         if (_iCoreExcelAnalyzeService.IsMergedRegionCell(j, i, sheet, ref firstRegionRow))  //2、单元格为合并单元格且不在合并区域左上角
     5                         {
     6                             if (firstRegionRow >= lastHeaderRowIndex && i != firstRegionRow)//合并单元格  第一行无值为cell合并
     7                             {
     8                                 int resultIndex = firstRegionRow - lastHeaderRowIndex;
     9 
    10                                 var oldModel =
    11                                     resultList.Select((p, d) => new { p, d })
    12                                         .Where(p => p.d == resultIndex)
    13                                         .Select(p => p.p).First();
    14                                 var regionValue = oldModel.GetType().GetProperty(property).GetValue(oldModel, null);//获得合并单元格第一行数据
    15                                 value = regionValue.ToString();
    16                             }
    17                         }
    18                         else   //1、单元格空值
    19                         {
    20                             nullcount++;
    21                         }
    22                    }

    注:

    1.第4行涉及方法IsMergedRegionCell()是用来判断当前空值单元格是否是合并单元格,并返回合并单元格起始行

    我们查阅NPOI接口得知,目前并不支持直接判断,只有通过自己的逻辑去判断是否是合并单元格(不知道是否是博主未查到准确的API,如有该API,请指出...)

     1         // 判断单元格是否被合并
     2         public bool IsMergedRegionCell(int cellIndex, int rowIndex,ISheet sheet,ref int firstRegionRow)
     3         {
     4             bool isMerged = false;
     5             var regionLists = GetMergedCellRegion(sheet);
     6 
     7             foreach (var cellRangeAddress in regionLists)
     8             {
     9                 for (int i = cellRangeAddress.FirstRow; i <= cellRangeAddress.LastRow; i++)
    10                 {
    11                     if (rowIndex == i)
    12                     {
    13                         for (int j = cellRangeAddress.FirstColumn; j <= cellRangeAddress.LastColumn; j++)
    14                         {
    15                             if (cellIndex == j)
    16                             {
    17                                 isMerged = true;
    18                                 firstRegionRow = cellRangeAddress.FirstRow;
    19                                 break;
    20                             }
    21                             else
    22                             {
    23                                 continue;
    24                             }
    25                         }
    26                     }
    27                     else
    28                     {
    29                         continue;
    30                     }
    31                 }
    32             }
    33 
    34             return isMerged;
    35         }
    36 
    37         // 获取合并区域信息
    38         private List<CellRangeAddress> GetMergedCellRegion(ISheet sheet)
    39         {
    40             int mergedRegionCellCount = sheet.NumMergedRegions;
    41             var returnList = new List<CellRangeAddress>();
    42 
    43             for (int i = 0; i < mergedRegionCellCount; i++)
    44             {
    45                 returnList.Add(sheet.GetMergedRegion(i));
    46             }
    47 
    48             return returnList;
    49         }

    博主只查阅到NPOI有sheet所有合并区域属性,以及获取某合并区域合并坐标方法...故做了此方法来做判断

    2.第6-16行则是在获取合并单元格值,具体思路是:

    合并坐标起始行不等于当前行,若等则代表有列合并(已经是空值),而我们暂不对列合并做值的特殊处理

    resultIndex是计算该合并单元格值已被读取到DTO中的索引

    oldModel是获得含有该合并单元格值的数据对象

     

    这样,我们就成功的读取到了左合并单元格的数据,在入库时稍作处理即可得到我们想要的“水位.潮汐性质”数据字段。

     

    至此,我们已经完成了绝大部分excel表格模板的解析工作。

    上述代码如有任何不对之处,欢迎指出,一定虚心请教~~~

     

    不过,博主的甲方特别难缠,最近又给了一个矩阵模板excel,让解析入库,还说有同样类型的模板很多个....

    意思很明显,这尼玛又得加班加点的搞了...

    模板样式如下:

    出发城市、到达城市内容、个数不定,意思就是连表头内容都是不确定的....

    还要求数据进库后,再能把筛选出来的数据按原模板顺序导出....

     

    好吧,吐血中~~~如果博主下周还活着,请关注下一篇文章查看解决方案(为什么是下周呢?因为尼玛这周末是最后期限...)

     

    原创文章,代码都是从自己项目里贴出来的。转载请注明出处哦,亲~~~

    转载于:https://www.cnblogs.com/csqb-511612371/p/4895548.html

    展开全文
  • 最近接到一个需求,需要把一份37万的excel数据解析并导入数据库, 分析 表格格式相对复杂包含很多合并单元格, 不符合通过navicat直接导入要求, 数据量比较大, 建议一次保存25条,否则会导致内存泄漏; 代码 1.引入依赖...

    前言
    最近接到一个需求,需要把一份37万的excel数据解析并导入数据库,
    分析
    表格格式相对复杂包含很多合并单元格, 不符合通过navicat直接导入的要求, 数据量比较大, 建议一次保存25条,否则会导致内存泄漏;
    代码
    1.引入依赖

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.9</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.9</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>3.9</version>
    </dependency>
    

    2.具体操作代码
    2.1.判断指定的单元格是否为合并单元格

    /**
     * 判断指定的单元格是否是合并单元格
     *
     * @param sheet
     * @param row    行下标
     * @param column 列下标
     * @return
     */
    private static boolean isMergedRegion(Sheet sheet, int row, int column) {
        //获取该sheet所有合并的单元格
        int sheetMergeCount = sheet.getNumMergedRegions();
        //循环判断 该单元格属于哪个合并单元格, 如果能找到对应的,就表示该单元格是合并单元格
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }
    

    2.2.获取合并单元格的值

    /**
     * 获取合并单元格的值
     *
     * @param sheet  sheet索引 从0开始
     * @param row    行索引 从0开始
     * @param column 列索引  从0开始
     * @return
     */
    public static String getMergedRegionValue(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress ca = sheet.getMergedRegion(i);
            int firstColumn = ca.getFirstColumn();
            int lastColumn = ca.getLastColumn();
            int firstRow = ca.getFirstRow();
            int lastRow = ca.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    Row fRow = sheet.getRow(firstRow);
                    Cell fCell = fRow.getCell(firstColumn);
                    return getCellValue(fCell);
                }
            }
        }
        return null;
    }
    

    2.3.获取单元格的值(不是合并单元格)

    /**
     * 获取单元格的值  先确定单元格的类型,然后根据类型 取值
     *
     * @param cell 单元格
     * @return
     */
    public static String getCellValue(Cell cell) {
        if (cell == null) return "";
        if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
            return cell.getStringCellValue();
        } else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
            return cell.getCellFormula();
        } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            return String.valueOf(cell.getNumericCellValue());
        }
        return "";
    }
    

    2.4.解析完一行数据后,判断对象的属性是否都为空

    /**
     * 判断一个对象的属性是否都为空,
     *
     * @param obj 对象
     * @return false : 至少有一个属性不为空, true: 该对象的属性全为空
     */
    public boolean allFieldIsNULL(Object obj) {
        Boolean flag = true;//都为空
        if (null == obj || "".equals(obj)) return flag;
        try {
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field : declaredFields) { // 循环该类,取出类中的每个属性
                field.setAccessible(true);// 把该类中的所有属性设置成 public
                Object object = field.get(obj); // object 是对象中的属性
                if (object instanceof CharSequence) { // 判断对象中的属性的类型,是否都是CharSequence的子类
                    if (!Objects.isNull(object)) { // 如果是他的子类,那么就可以用ObjectUtils.isEmpty进行比较
                        flag = false;//不为空
                    }
                } else { //如果不是那就直接用null判断
                    if (!(null == object || "".equals(object))) {
                        flag = false;//不为空
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;//false:不都为空
    }
    

    2.5.解析excel的工具类

    /**
     * 读取excel文件
     *
     * @param
     * @param sheetIndex    sheet页下标:从0开始
     * @param startReadLine 开始读取的行:从0开始
     * @param tailLine      结束行
     */
    public void readExcel(String path, int sheetIndex, int startReadLine, int tailLine) {
        Workbook wb = null;
        try {
            wb = WorkbookFactory.create(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        }
        //读取excel表中的sheet, 参数为sheet的索引值(从0开始)
        Sheet sheet = wb.getSheetAt(sheetIndex);
        Row row = null;
        Boolean save = false;
        //获取该sheet的最后一行数据的索引
        int lastRowNum = sheet.getLastRowNum();
        ArrayList<CmsIndexCategory> list = new ArrayList<>();
        //外循环是循环行,内循环是循环每行的单元格
        for (int i = startReadLine; i <= lastRowNum; i++) {
            CmsIndexCategory indexCategory = new CmsIndexCategory();
            //根据行索引获取行对象(单元格集合)
            row = sheet.getRow(i);
            //遍历行的单元格,并解析
            for (Cell c : row) {
                String returnStr = "";
                String trim = "";
                //设置该单元格的数据的类型为String
                c.setCellType(Cell.CELL_TYPE_STRING);
                boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex());
                // 判断是否具有合并单元格
                if (isMerge) {
                //如果是合并单元格,就获取合并单元格的值
                    returnStr = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex()).toString();
                } else {
                //不是合并单元格直接获取单元格的值
                    returnStr = getCellValue(c).toString();
                }
                if (Objects.nonNull(returnStr) && StringUtils.isNotEmpty(returnStr)) {
                    trim = returnStr.trim();
                    //封装结果集,一行数据封装为一个对象
                    if (c.getColumnIndex() == 0) {
                        indexCategory.setAgencyBrand(trim);
                    } else if (c.getColumnIndex() == 1) {
                        indexCategory.setCompanyName(trim);
                    } else if (c.getColumnIndex() == 2) {
                        indexCategory.setIndustryField(trim);
                    } else if (c.getColumnIndex() == 3) {
                        indexCategory.setDetectionField(trim);
                    } else if (c.getColumnIndex() == 4) {
                        indexCategory.setDetectionObj(trim);
                    } else if (c.getColumnIndex() == 5) {
                        indexCategory.setSampleCategory(trim);
                    } else if (c.getColumnIndex() == 6) {
                        indexCategory.setDetectionRange(trim);
                    } else if (c.getColumnIndex() == 7) {
                        indexCategory.setDetectionItem(trim);
                    } else if (c.getColumnIndex() == 8) {
                        indexCategory.setDetectionStandard(trim);
                    }
                }
            }
            //判断一个对象的属性是否都为空, true:都为空  , false: 不都为空
            if (!allFieldIsNULL(indexCategory)) {
                //该对象不都为空的情况下,添加到集合中
                list.add(indexCategory);
            }
            //一次保存25条数据,最后一次数据不够25条也进行保存
            if (list.size() == 25 || i == lastRowNum) {
                save = this.iCmsIndexCategoryService.saveBatch(list);
                System.out.println("==================================================第------" + (i + 1) + "---------行保存结果为======================================== " + save);
                list.clear();
            }
        }
    }
    

    3.具体实践

    @GetMapping("/excel")
    public String excel2() {
        this.readExcel("C:\\Users\\yangmin\\Desktop\\我要测资料\\特色检测项目\\7.xlsx", 0, 0, 0);
        return "完成";
    }
    
    展开全文
  • Android中解析读取复杂word,excel,ppt等方法

    万次阅读 热门讨论 2016-08-02 17:49:20
    查阅了下资料,发现Android中最传统的直接解析读取word,excel的方法主要用了java里第三方包,比如利用tm-extractors-0.4.jar和jxl.jar等,下面附上代码和效果图。  读取word用了tm-extractors-0.4.jar包,代码如

            前段时间在尝试做一个Android里的万能播放器,能播放各种格式的软件,其中就涉及到了最常用的office软件。查阅了下资料,发现Android中最传统的直接解析读取word,excel的方法主要用了java里第三方包,比如利用tm-extractors-0.4.jar和jxl.jar等,下面附上代码和效果图。

            读取word用了tm-extractors-0.4.jar包,代码如下:

      

    package com.example.readword;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    import org.textmining.text.extraction.WordExtractor;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.widget.TextView;
    
    
    public class MainActivity extends Activity {
        /** Called when the activity is first created. */
    
        private TextView text;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            text = (TextView) findViewById(R.id.text);
    
            String str = readWord("/storage/emulated/0/ArcGIS/localtilelayer/11.doc");
            text.setText(str.trim().replace("", ""));
        }
    
        public String readWord(String file){
            //创建输入流用来读取doc文件
            FileInputStream in;
            String text = null;
            try {
                in = new FileInputStream(new File(file));
                WordExtractor extractor = null;
                //创建WordExtractor
                extractor = new WordExtractor();
                //进行提取对doc文件
                text = extractor.extractText(in);
            }
            catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            return text;
        }
    }

            效果图如下:



           只是从网上随便下载的一个文档,我们可以看出,虽然能读取,但是格式的效果并不佳,而且只能读取doc,不能读取docx格式,也不能读取doc里的图片。另外就是加入使用WPF打开过这个doc的话,将无法再次读取(对于只安装WPF的我简直是个灾难)

           然后是用jxl读取excel的代码,这个代码不是很齐,就写了个解析的,将excel里每行每列都解析了出来,然后自己可以重新再编辑,代码如下:

         

    package com.readexl;
    
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    import android.os.Bundle;
    import android.os.Environment;
    import android.app.Activity;
    import android.text.method.ScrollingMovementMethod;
    import android.view.Menu;
    import android.widget.TextView;
    
    import jxl.*;
    
    public class MainActivity extends Activity {
        TextView txt = null;
        public String filePath_xls = Environment.getExternalStorageDirectory()
                + "/case.xls";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            txt = (TextView)findViewById(R.id.txt_show);
            txt.setMovementMethod(ScrollingMovementMethod.getInstance());
            readExcel();
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        public void readExcel() {
            try {
                /**
                 * 后续考虑问题,比如Excel里面的图片以及其他数据类型的读取
                 **/
    
                InputStream is = new FileInputStream(filePath_xls);
                //Workbook book = Workbook.getWorkbook(new File("mnt/sdcard/test.xls"));
                Workbook book = Workbook.getWorkbook(is);
    
                int num = book.getNumberOfSheets();
                txt.setText("the num of sheets is " + num+ "\n");
                // 获得第一个工作表对象
                Sheet sheet = book.getSheet(0);
                int Rows = sheet.getRows();
                int Cols = sheet.getColumns();
                txt.append("the name of sheet is " + sheet.getName() + "\n");
                txt.append("total rows is " + Rows + "\n");
                txt.append("total cols is " + Cols + "\n");
                for (int i = 0; i < Cols; ++i) {
                    for (int j = 0; j < Rows; ++j) {
                        // getCell(Col,Row)获得单元格的值
                        txt.append("contents:" + sheet.getCell(i,j).getContents() + "\n");
                    }
                }
                book.close();
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    
    }

    效果图如下:

            

           好吧,这只是个半成品,不过,这个方法肯定是行得通的。

           之前说了这么多,很明白的意思就是我对于这两种方法都不是很满意。在这里,我先说下doc和docx的区别(xls和xlsx,ppt和pptx等区别都和此类似)

           众所周知的是doc03及之前版本word所保存的格式,docx07版本之后保存的格式,简单的说,在doc中,微软还是用二进制存储方式;在docx中微软开始用xml方式,docx实际上成了一个打包的ZIP压缩文件。doc解压得到的是没有扩展名的文件碎片,而docx解压可以得到一个XML和几个包含信息的文件夹。两者比较的结论就是docx更小,而且要读取图片更容易。(参考http://www.zhihu.com/question/21547795)

      好吧,回到正题。如何才能解析各种word,excel等能保留原来格式并且解析里面的图片,表格或附件等内容呢。那当然就是html了!不得不承认html对于页面,表格等展示的效果确是是很强大的,原生很难写出这样的效果。在网上找了诸多的资料,以及各个大神的代码,自己又再此基础上修改了下,实现的效果还不错吧。

      利用的包是POI(一堆很强大的包,可以解析几乎所有的office软件,这里以doc,docx,xls,xlsx为例)


    读取文件后根据不同文件类型分别进行操作。

    public void read() {
        if(!myFile.exists()){
            if (this.nameStr.endsWith(".doc")) {
                this.getRange();
                this.makeFile();
                this.readDOC();
            }
            if (this.nameStr.endsWith(".docx")) {
                this.makeFile();
                this.readDOCX();
            }
            if (this.nameStr.endsWith(".xls")) {
                try {
                    this.makeFile();
                    this.readXLS();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (this.nameStr.endsWith(".xlsx")) {
                try{
                    this.makeFile();
                    this.readXLSX();
                }catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        returnPath = "file:///" + myFile;
        // this.view.loadUrl("file:///" + this.htmlPath);
        System.out.println("htmlPath" + this.htmlPath);
    
    }
    先贴上公用的方法,主要是设置生成的html文件保存地址:

    public void makeFile() {
        String sdStateString = android.os.Environment.getExternalStorageState();// 获取外部存储状态
        if (sdStateString.equals(android.os.Environment.MEDIA_MOUNTED)) {// 确认sd卡存在,原理不知,媒体安装??
            try {
                File sdFile = android.os.Environment
                        .getExternalStorageDirectory();// 获取扩展设备的文件目录
                String path = sdFile.getAbsolutePath() + File.separator
                        + "library";// 得到sd卡(扩展设备)的绝对路径+"/"+xiao
                File dirFile = new File(path);// 获取xiao文件夹地址
                if (!dirFile.exists()) {// 如果不存在
                    dirFile.mkdir();// 创建目录
                }
                File myFile = new File(path + File.separator +filename+ ".html");// 获取my.html的地址
                if (!myFile.exists()) {// 如果不存在
                    myFile.createNewFile();// 创建文件
                }
                this.htmlPath = myFile.getAbsolutePath();// 返回路径
            } catch (Exception e) {
            }
        }
    }
    然后是读取doc:

    private void getRange() {
        FileInputStream in = null;
        POIFSFileSystem pfs = null;
    
        try {
            in = new FileInputStream(nameStr);
            pfs = new POIFSFileSystem(in);
            hwpf = new HWPFDocument(pfs);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
        range = hwpf.getRange();
    
        pictures = hwpf.getPicturesTable().getAllPictures();
    
        tableIterator = new TableIterator(range);
    
    }
    public void readDOC() {
    
        try {
            myFile = new File(htmlPath);
            output = new FileOutputStream(myFile);
            presentPicture=0;
            String head = "<html><meta charset=\"utf-8\"><body>";
            String tagBegin = "<p>";
            String tagEnd = "</p>";
            output.write(head.getBytes());
            int numParagraphs = range.numParagraphs();// 得到页面所有的段落数
            for (int i = 0; i < numParagraphs; i++) { // 遍历段落数
                Paragraph p = range.getParagraph(i); // 得到文档中的每一个段落
                if (p.isInTable()) {
                    int temp = i;
                    if (tableIterator.hasNext()) {
                        String tableBegin = "<table style=\"border-collapse:collapse\" border=1 bordercolor=\"black\">";
                        String tableEnd = "</table>";
                        String rowBegin = "<tr>";
                        String rowEnd = "</tr>";
                        String colBegin = "<td>";
                        String colEnd = "</td>";
                        Table table = tableIterator.next();
                        output.write(tableBegin.getBytes());
                        int rows = table.numRows();
                        for (int r = 0; r < rows; r++) {
                            output.write(rowBegin.getBytes());
                            TableRow row = table.getRow(r);
                            int cols = row.numCells();
                            int rowNumParagraphs = row.numParagraphs();
                            int colsNumParagraphs = 0;
                            for (int c = 0; c < cols; c++) {
                                output.write(colBegin.getBytes());
                                TableCell cell = row.getCell(c);
                                int max = temp + cell.numParagraphs();
                                colsNumParagraphs = colsNumParagraphs
                                        + cell.numParagraphs();
                                for (int cp = temp; cp < max; cp++) {
                                    Paragraph p1 = range.getParagraph(cp);
                                    output.write(tagBegin.getBytes());
                                    writeParagraphContent(p1);
                                    output.write(tagEnd.getBytes());
                                    temp++;
                                }
                                output.write(colEnd.getBytes());
                            }
                            int max1 = temp + rowNumParagraphs;
                            for (int m = temp + colsNumParagraphs; m < max1; m++) {
                                temp++;
                            }
                            output.write(rowEnd.getBytes());
                        }
                        output.write(tableEnd.getBytes());
                    }
                    i = temp;
                } else {
                    output.write(tagBegin.getBytes());
                    writeParagraphContent(p);
                    output.write(tagEnd.getBytes());
                }
            }
            String end = "</body></html>";
            output.write(end.getBytes());
            output.close();
        } catch (Exception e) {
    
            System.out.println("readAndWrite Exception:"+e.getMessage());
            e.printStackTrace();
        }
    }
    读取docx

    public void readDOCX() {
        String river = "";
        try {
            this.myFile = new File(this.htmlPath);// new一个File,路径为html文件
            this.output = new FileOutputStream(this.myFile);// new一个流,目标为html文件
            presentPicture=0;
            String head = "<!DOCTYPE><html><meta charset=\"utf-8\"><body>";// 定义头文件,我在这里加了utf-8,不然会出现乱码
            String end = "</body></html>";
            String tagBegin = "<p>";// 段落开始,标记开始?
            String tagEnd = "</p>";// 段落结束
            String tableBegin = "<table style=\"border-collapse:collapse\" border=1 bordercolor=\"black\">";
            String tableEnd = "</table>";
            String rowBegin = "<tr>";
            String rowEnd = "</tr>";
            String colBegin = "<td>";
            String colEnd = "</td>";
            String style = "style=\"";
            this.output.write(head.getBytes());// 写如头部
            ZipFile xlsxFile = new ZipFile(new File(this.nameStr));
            ZipEntry sharedStringXML = xlsxFile.getEntry("word/document.xml");
            InputStream inputStream = xlsxFile.getInputStream(sharedStringXML);
            XmlPullParser xmlParser = Xml.newPullParser();
            xmlParser.setInput(inputStream, "utf-8");
            int evtType = xmlParser.getEventType();
            boolean isTable = false; // 是表格 用来统计 列 行 数
            boolean isSize = false; // 大小状态
            boolean isColor = false; // 颜色状态
            boolean isCenter = false; // 居中状态
            boolean isRight = false; // 居右状态
            boolean isItalic = false; // 是斜体
            boolean isUnderline = false; // 是下划线
            boolean isBold = false; // 加粗
            boolean isR = false; // 在那个r中
            boolean isStyle = false;
            int pictureIndex = 1; // docx 压缩包中的图片名 iamge1 开始 所以索引从1开始
            while (evtType != XmlPullParser.END_DOCUMENT) {
                switch (evtType) {
    
                    // 开始标签
                    case XmlPullParser.START_TAG:
                        String tag = xmlParser.getName();
    
                        if (tag.equalsIgnoreCase("r")) {
                            isR = true;
                        }
                        if (tag.equalsIgnoreCase("u")) { // 判断下划线
                            isUnderline = true;
                        }
                        if (tag.equalsIgnoreCase("jc")) { // 判断对齐方式
                            String align = xmlParser.getAttributeValue(0);
                            if (align.equals("center")) {
                                this.output.write("<center>".getBytes());
                                isCenter = true;
                            }
                            if (align.equals("right")) {
                                this.output.write("<div align=\"right\">"
                                        .getBytes());
                                isRight = true;
                            }
                        }
    
                        if (tag.equalsIgnoreCase("color")) { // 判断颜色
    
                            String color = xmlParser.getAttributeValue(0);
    
                            this.output
                                    .write(("<span style=\"color:" + color + ";\">")
                                            .getBytes());
                            isColor = true;
                        }
                        if (tag.equalsIgnoreCase("sz")) { // 判断大小
                            if (isR == true) {
                                int size = decideSize(Integer.valueOf(xmlParser
                                        .getAttributeValue(0)));
                                this.output.write(("<font size=" + size + ">")
                                        .getBytes());
                                isSize = true;
                            }
                        }
                        // 下面是表格处理
                        if (tag.equalsIgnoreCase("tbl")) { // 检测到tbl 表格开始
                            this.output.write(tableBegin.getBytes());
                            isTable = true;
                        }
                        if (tag.equalsIgnoreCase("tr")) { // 行
                            this.output.write(rowBegin.getBytes());
                        }
                        if (tag.equalsIgnoreCase("tc")) { // 列
                            this.output.write(colBegin.getBytes());
                        }
    
                        if (tag.equalsIgnoreCase("pic")) { // 检测到标签 pic 图片
                            String entryName_jpeg = "word/media/image"
                                    + pictureIndex + ".jpeg";
                            String entryName_png = "word/media/image"
                                    + pictureIndex + ".png";
                            String entryName_gif = "word/media/image"
                                    + pictureIndex + ".gif";
                            String entryName_wmf = "word/media/image"
                                    + pictureIndex + ".wmf";
                            ZipEntry sharePicture = null;
                            InputStream pictIS = null;
                            sharePicture = xlsxFile.getEntry(entryName_jpeg);
                            // 一下为读取docx的图片 转化为流数组
                            if (sharePicture == null) {
                                sharePicture = xlsxFile.getEntry(entryName_png);
                            }
                            if(sharePicture == null){
                                sharePicture = xlsxFile.getEntry(entryName_gif);
                            }
                            if(sharePicture == null){
                                sharePicture = xlsxFile.getEntry(entryName_wmf);
                            }
    
                            if(sharePicture != null){
                                pictIS = xlsxFile.getInputStream(sharePicture);
                                ByteArrayOutputStream pOut = new ByteArrayOutputStream();
                                byte[] bt = null;
                                byte[] b = new byte[1000];
                                int len = 0;
                                while ((len = pictIS.read(b)) != -1) {
                                    pOut.write(b, 0, len);
                                }
                                pictIS.close();
                                pOut.close();
                                bt = pOut.toByteArray();
                                Log.i("byteArray", "" + bt);
                                if (pictIS != null)
                                    pictIS.close();
                                if (pOut != null)
                                    pOut.close();
                                writeDOCXPicture(bt);
                            }
    
                            pictureIndex++; // 转换一张后 索引+1
                        }
    
                        if (tag.equalsIgnoreCase("b")) { // 检测到加粗标签
                            isBold = true;
                        }
                        if (tag.equalsIgnoreCase("p")) {// 检测到 p 标签
                            if (isTable == false) { // 如果在表格中 就无视
                                this.output.write(tagBegin.getBytes());
                            }
                        }
                        if (tag.equalsIgnoreCase("i")) { // 斜体
                            isItalic = true;
                        }
                        // 检测到值 标签
                        if (tag.equalsIgnoreCase("t")) {
                            if (isBold == true) { // 加粗
                                this.output.write("<b>".getBytes());
                            }
                            if (isUnderline == true) { // 检测到下划线标签,输入<u>
                                this.output.write("<u>".getBytes());
                            }
                            if (isItalic == true) { // 检测到斜体标签,输入<i>
                                output.write("<i>".getBytes());
                            }
                            river = xmlParser.nextText();
                            this.output.write(river.getBytes()); // 写入数值
                            if (isItalic == true) { // 检测到斜体标签,在输入值之后,输入</i>,并且斜体状态=false
                                this.output.write("</i>".getBytes());
                                isItalic = false;
                            }
                            if (isUnderline == true) {// 检测到下划线标签,在输入值之后,输入</u>,并且下划线状态=false
                                this.output.write("</u>".getBytes());
                                isUnderline = false;
                            }
                            if (isBold == true) { // 加粗
                                this.output.write("</b>".getBytes());
                                isBold = false;
                            }
                            if (isSize == true) { // 检测到大小设置,输入结束标签
                                this.output.write("</font>".getBytes());
                                isSize = false;
                            }
                            if (isColor == true) { // 检测到颜色设置存在,输入结束标签
                                this.output.write("</span>".getBytes());
                                isColor = false;
                            }
                            if (isCenter == true) { // 检测到居中,输入结束标签
                                this.output.write("</center>".getBytes());
                                isCenter = false;
                            }
                            if (isRight == true) { // 居右不能使用<right></right>,使用div可能会有状况,先用着
                                this.output.write("</div>".getBytes());
                                isRight = false;
                            }
                        }
                        break;
                    // 结束标签
                    case XmlPullParser.END_TAG:
                        String tag2 = xmlParser.getName();
                        if (tag2.equalsIgnoreCase("tbl")) { // 检测到表格结束,更改表格状态
                            this.output.write(tableEnd.getBytes());
                            isTable = false;
                        }
                        if (tag2.equalsIgnoreCase("tr")) { // 行结束
                            this.output.write(rowEnd.getBytes());
                        }
                        if (tag2.equalsIgnoreCase("tc")) { // 列结束
                            this.output.write(colEnd.getBytes());
                        }
                        if (tag2.equalsIgnoreCase("p")) { // p结束,如果在表格中就无视
                            if (isTable == false) {
                                this.output.write(tagEnd.getBytes());
                            }
                        }
                        if (tag2.equalsIgnoreCase("r")) {
                            isR = false;
                        }
                        break;
                    default:
                        break;
                }
                evtType = xmlParser.next();
            }
            this.output.write(end.getBytes());
        } catch (ZipException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        if (river == null) {
            river = "解析文件出现问题";
        }
    }
    
    读取xls:

    public StringBuffer readXLS() throws Exception {
    
            myFile = new File(htmlPath);
            output = new FileOutputStream(myFile);
            lsb.append("<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>");
            lsb.append("<head><meta http-equiv=Content-Type content='text/html; charset=utf-8'><meta name=ProgId content=Excel.Sheet>");
            HSSFSheet sheet = null;
    
            String excelFileName = nameStr;
            try {
            HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(
            excelFileName)); // 获整个Excel
    
            for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
            sheet = workbook.getSheetAt(sheetIndex);// 获所有的sheet
            String sheetName = workbook.getSheetName(sheetIndex); // sheetName
            if (workbook.getSheetAt(sheetIndex) != null) {
            sheet = workbook.getSheetAt(sheetIndex);// 获得不为空的这个sheet
            if (sheet != null) {
            int firstRowNum = sheet.getFirstRowNum(); // 第一行
            int lastRowNum = sheet.getLastRowNum(); // 最后一行
            lsb.append("<table width=\"100%\" style=\"border:1px solid #000;border-width:1px 0 0 1px;margin:2px 0 2px 0;border-collapse:collapse;\">");
    
            for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) {
            if (sheet.getRow(rowNum) != null) {// 如果行不为空,
            HSSFRow row = sheet.getRow(rowNum);
            short firstCellNum = row.getFirstCellNum(); // 该行的第一个单元格
            short lastCellNum = row.getLastCellNum(); // 该行的最后一个单元格
            int height = (int) (row.getHeight() / 15.625); // 行的高度
            lsb.append("<tr height=\""
            + height
            + "\" style=\"border:1px solid #000;border-width:0 1px 1px 0;margin:2px 0 2px 0;\">");
            for (short cellNum = firstCellNum; cellNum <= lastCellNum; cellNum++) { // 循环该行的每一个单元格
            HSSFCell cell = row.getCell(cellNum);
            if (cell != null) {
            if (cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
            continue;
            } else {
            StringBuffer tdStyle = new StringBuffer(
            "<td style=\"border:1px solid #000; border-width:0 1px 1px 0;margin:2px 0 2px 0; ");
            HSSFCellStyle cellStyle = cell
            .getCellStyle();
            HSSFPalette palette = workbook
            .getCustomPalette(); // 类HSSFPalette用于求颜色的国际标准形式
            HSSFColor hColor = palette
            .getColor(cellStyle
            .getFillForegroundColor());
            HSSFColor hColor2 = palette
            .getColor(cellStyle
            .getFont(workbook)
            .getColor());
    
            String bgColor = convertToStardColor(hColor);// 背景颜色
            short boldWeight = cellStyle
            .getFont(workbook)
            .getBoldweight(); // 字体粗细
            short fontHeight = (short) (cellStyle
            .getFont(workbook)
            .getFontHeight() / 2); // 字体大小
            String fontColor = convertToStardColor(hColor2); // 字体颜色
            if (bgColor != null
            && !"".equals(bgColor
            .trim())) {
            tdStyle.append(" background-color:"
            + bgColor + "; ");
            }
            if (fontColor != null
            && !"".equals(fontColor
            .trim())) {
            tdStyle.append(" color:"
            + fontColor + "; ");
            }
            tdStyle.append(" font-weight:"
            + boldWeight + "; ");
            tdStyle.append(" font-size: "
            + fontHeight + "%;");
            lsb.append(tdStyle + "\"");
    
            int width = (int) (sheet.getColumnWidth(cellNum) / 35.7);
    
            int cellReginCol = getMergerCellRegionCol(
            sheet, rowNum, cellNum); // 合并的列(solspan)
            int cellReginRow = getMergerCellRegionRow(
            sheet, rowNum, cellNum);// 合并的行(rowspan)
            String align = convertVerticalAlignToHtml(cellStyle
            .getAlignment()); //
            String vAlign = convertVerticalAlignToHtml(cellStyle
            .getVerticalAlignment());
    
            lsb.append(" align=\"" + align
            + "\" valign=\"" + vAlign
            + "\" width=\"" + width
            + "\" ");
    
            lsb.append(" colspan=\""
            + cellReginCol
            + "\" rowspan=\""
            + cellReginRow + "\"");
            lsb.append(">" + getCellValue(cell)
            + "</td>");
            }
            }
            }
            lsb.append("</tr>");
            }
            }
            }
    
            }
    
            }
            output.write(lsb.toString().getBytes());
            } catch (FileNotFoundException e) {
            throw new Exception("文件" + excelFileName + " 没有找到!");
            } catch (IOException e) {
            throw new Exception("文件" + excelFileName + " 处理错误("
            + e.getMessage() + ")!");
            }
            return lsb;
            }
    读取xlsx:

    public void readXLSX() {
            try {
            this.myFile = new File(this.htmlPath);// new一个File,路径为html文件
            this.output = new FileOutputStream(this.myFile);// new一个流,目标为html文件
            String head = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\"http://www.w3.org/TR/html4/loose.dtd\"><html><meta charset=\"utf-8\"><head></head><body>";// 定义头文件,我在这里加了utf-8,不然会出现乱码
            String tableBegin = "<table style=\"border-collapse:collapse\" border=1 bordercolor=\"black\">";
            String tableEnd = "</table>";
            String rowBegin = "<tr>";
            String rowEnd = "</tr>";
            String colBegin = "<td>";
            String colEnd = "</td>";
            String end = "</body></html>";
            this.output.write(head.getBytes());
            this.output.write(tableBegin.getBytes());
            String str = "";
            String v = null;
            boolean flat = false;
            List<String> ls = new ArrayList<String>();
            try {
            ZipFile xlsxFile = new ZipFile(new File(this.nameStr));// 地址
            ZipEntry sharedStringXML = xlsxFile
            .getEntry("xl/sharedStrings.xml");// 共享字符串
            InputStream inputStream = xlsxFile
            .getInputStream(sharedStringXML);// 输入流 目标上面的共享字符串
            XmlPullParser xmlParser = Xml.newPullParser();// new 解析器
            xmlParser.setInput(inputStream, "utf-8");// 设置解析器类型
            int evtType = xmlParser.getEventType();// 获取解析器的事件类型
            while (evtType != XmlPullParser.END_DOCUMENT) {// 如果不等于 文档结束
            switch (evtType) {
            case XmlPullParser.START_TAG: // 标签开始
            String tag = xmlParser.getName();
            if (tag.equalsIgnoreCase("t")) {
            ls.add(xmlParser.nextText());
            }
            break;
            case XmlPullParser.END_TAG: // 标签结束
            break;
    default:
            break;
            }
            evtType = xmlParser.next();
            }
            ZipEntry sheetXML = xlsxFile
            .getEntry("xl/worksheets/sheet1.xml");
            InputStream inputStreamsheet = xlsxFile
            .getInputStream(sheetXML);
            XmlPullParser xmlParsersheet = Xml.newPullParser();
            xmlParsersheet.setInput(inputStreamsheet, "utf-8");
            int evtTypesheet = xmlParsersheet.getEventType();
            this.output.write(rowBegin.getBytes());
            int i = -1;
            while (evtTypesheet != XmlPullParser.END_DOCUMENT) {
            switch (evtTypesheet) {
            case XmlPullParser.START_TAG: // 标签开始
            String tag = xmlParsersheet.getName();
            if (tag.equalsIgnoreCase("row")) {
            } else {
            if (tag.equalsIgnoreCase("c")) {
            String t = xmlParsersheet.getAttributeValue(
            null, "t");
            if (t != null) {
            flat = true;
            System.out.println(flat + "有");
            } else {// 没有数据时 找了我n年,终于找到了 输入<td></td> 表示空格
            this.output.write(colBegin.getBytes());
            this.output.write(colEnd.getBytes());
            System.out.println(flat + "没有");
            flat = false;
            }
            } else {
            if (tag.equalsIgnoreCase("v")) {
            v = xmlParsersheet.nextText();
            this.output.write(colBegin.getBytes());
            if (v != null) {
            if (flat) {
            str = ls.get(Integer.parseInt(v));
            } else {
            str = v;
            }
            this.output.write(str.getBytes());
            this.output.write(colEnd.getBytes());
            }
            }
            }
            }
            break;
            case XmlPullParser.END_TAG:
            if (xmlParsersheet.getName().equalsIgnoreCase("row")
            && v != null) {
            if (i == 1) {
            this.output.write(rowEnd.getBytes());
            this.output.write(rowBegin.getBytes());
            i = 1;
            } else {
            this.output.write(rowBegin.getBytes());
            }
            }
            break;
            }
            evtTypesheet = xmlParsersheet.next();
            }
            System.out.println(str);
            } catch (ZipException e) {
            e.printStackTrace();
            } catch (IOException e) {
            e.printStackTrace();
            } catch (XmlPullParserException e) {
            e.printStackTrace();
            }
            if (str == null) {
            str = "解析文件出现问题";
            }
            this.output.write(rowEnd.getBytes());
            this.output.write(tableEnd.getBytes());
            this.output.write(end.getBytes());
            } catch (Exception e) {
            System.out.println("readAndWrite Exception");
            }
            }
    
    单元格的操作:

    /**
     * 取得单元格的值
     *
     * @param cell
     * @return
     * @throws IOException
     */
    private static Object getCellValue(HSSFCell cell) throws IOException {
            Object value = "";
            if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
            value = cell.getRichStringCellValue().toString();
            } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
            if (HSSFDateUtil.isCellDateFormatted(cell)) {
            Date date = (Date) cell.getDateCellValue();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            value = sdf.format(date);
            } else {
            double value_temp = (double) cell.getNumericCellValue();
            BigDecimal bd = new BigDecimal(value_temp);
            BigDecimal bd1 = bd.setScale(3, bd.ROUND_HALF_UP);
            value = bd1.doubleValue();
    
            DecimalFormat format = new DecimalFormat("#0.###");
            value = format.format(cell.getNumericCellValue());
    
            }
            }
            if (cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
            value = "";
            }
            return value;
            }
    
    /**
     * 判断单元格在不在合并单元格范围内,如果是,获取其合并的列数。
     *
     * @param sheet
     *            工作表
     * @param cellRow
     *            被判断的单元格的行号
     * @param cellCol
     *            被判断的单元格的列号
     * @return
     * @throws IOException
     */
    private static int getMergerCellRegionCol(HSSFSheet sheet, int cellRow,
            int cellCol) throws IOException {
            int retVal = 0;
            int sheetMergerCount = sheet.getNumMergedRegions();
            for (int i = 0; i < sheetMergerCount; i++) {
            CellRangeAddress cra = (CellRangeAddress) sheet.getMergedRegion(i);
            int firstRow = cra.getFirstRow(); // 合并单元格CELL起始行
            int firstCol = cra.getFirstColumn(); // 合并单元格CELL起始列
            int lastRow = cra.getLastRow(); // 合并单元格CELL结束行
            int lastCol = cra.getLastColumn(); // 合并单元格CELL结束列
            if (cellRow >= firstRow && cellRow <= lastRow) { // 判断该单元格是否是在合并单元格中
            if (cellCol >= firstCol && cellCol <= lastCol) {
            retVal = lastCol - firstCol + 1; // 得到合并的列数
            break;
            }
            }
            }
            return retVal;
            }
    
    /**
     * 判断单元格是否是合并的单格,如果是,获取其合并的行数。
     *
     * @param sheet
     *            表单
     * @param cellRow
     *            被判断的单元格的行号
     * @param cellCol
     *            被判断的单元格的列号
     * @return
     * @throws IOException
     */
    private static int getMergerCellRegionRow(HSSFSheet sheet, int cellRow,
            int cellCol) throws IOException {
            int retVal = 0;
            int sheetMergerCount = sheet.getNumMergedRegions();
            for (int i = 0; i < sheetMergerCount; i++) {
            CellRangeAddress cra = (CellRangeAddress) sheet.getMergedRegion(i);
            int firstRow = cra.getFirstRow(); // 合并单元格CELL起始行
            int firstCol = cra.getFirstColumn(); // 合并单元格CELL起始列
            int lastRow = cra.getLastRow(); // 合并单元格CELL结束行
            int lastCol = cra.getLastColumn(); // 合并单元格CELL结束列
            if (cellRow >= firstRow && cellRow <= lastRow) { // 判断该单元格是否是在合并单元格中
            if (cellCol >= firstCol && cellCol <= lastCol) {
            retVal = lastRow - firstRow + 1; // 得到合并的行数
            break;
            }
            }
            }
            return 0;
            }
    
    /**
     * 单元格背景色转换
     *
     * @param hc
     * @return
     */
    private String convertToStardColor(HSSFColor hc) {
            StringBuffer sb = new StringBuffer("");
            if (hc != null) {
            int a = HSSFColor.AUTOMATIC.index;
            int b = hc.getIndex();
            if (a == b) {
            return null;
            }
            sb.append("#");
            for (int i = 0; i < hc.getTriplet().length; i++) {
            String str;
            String str_tmp = Integer.toHexString(hc.getTriplet()[i]);
            if (str_tmp != null && str_tmp.length() < 2) {
            str = "0" + str_tmp;
            } else {
            str = str_tmp;
            }
            sb.append(str);
            }
            }
            return sb.toString();
            }
    
    /**
     * 单元格小平对齐
     *
     * @param alignment
     * @return
     */
    private String convertAlignToHtml(short alignment) {
            String align = "left";
            switch (alignment) {
            case HSSFCellStyle.ALIGN_LEFT:
            align = "left";
            break;
            case HSSFCellStyle.ALIGN_CENTER:
            align = "center";
            break;
            case HSSFCellStyle.ALIGN_RIGHT:
            align = "right";
            break;
    default:
            break;
            }
            return align;
            }
    
    /**
     * 单元格垂直对齐
     *
     * @param verticalAlignment
     * @return
     */
    private String convertVerticalAlignToHtml(short verticalAlignment) {
            String valign = "middle";
            switch (verticalAlignment) {
            case HSSFCellStyle.VERTICAL_BOTTOM:
            valign = "bottom";
            break;
            case HSSFCellStyle.VERTICAL_CENTER:
            valign = "center";
            break;
            case HSSFCellStyle.VERTICAL_TOP:
            valign = "top";
            break;
    default:
            break;
            }
            return valign;
            }
    
    public void makeFile() {
            String sdStateString = android.os.Environment.getExternalStorageState();// 获取外部存储状态
            if (sdStateString.equals(android.os.Environment.MEDIA_MOUNTED)) {// 确认sd卡存在,原理不知,媒体安装??
            try {
            File sdFile = android.os.Environment
            .getExternalStorageDirectory();// 获取扩展设备的文件目录
            String path = sdFile.getAbsolutePath() + File.separator
            + "library";// 得到sd卡(扩展设备)的绝对路径+"/"+xiao
            File dirFile = new File(path);// 获取xiao文件夹地址
            if (!dirFile.exists()) {// 如果不存在
            dirFile.mkdir();// 创建目录
            }
            File myFile = new File(path + File.separator +filename+ ".html");// 获取my.html的地址
            if (!myFile.exists()) {// 如果不存在
            myFile.createNewFile();// 创建文件
            }
            this.htmlPath = myFile.getAbsolutePath();// 返回路径
            } catch (Exception e) {
            }
            }
            }
    保存和读取图片:

    /* 用来在sdcard上创建图片 */
    public void makePictureFile() {
            String sdString = android.os.Environment.getExternalStorageState();// 获取外部存储状态
            if (sdString.equals(android.os.Environment.MEDIA_MOUNTED)) {// 确认sd卡存在,原理不知
            try {
            File picFile = android.os.Environment
            .getExternalStorageDirectory();// 获取sd卡目录
            String picPath = picFile.getAbsolutePath() + File.separator
            + "library";// 创建目录,上面有解释
            File picDirFile = new File(picPath);
            if (!picDirFile.exists()) {
            picDirFile.mkdir();
            }
            File pictureFile = new File(picPath + File.separator
            +getFileName(nameStr)+ presentPicture + ".jpg");// 创建jpg文件,方法与html相同
            if (!pictureFile.exists()) {
            pictureFile.createNewFile();
            }
            this.picturePath = pictureFile.getAbsolutePath();// 获取jpg文件绝对路径
            } catch (Exception e) {
            System.out.println("PictureFile Catch Exception");
            }
            }
            }
    
    public String getFileName(String pathandname){
    
            int start=pathandname.lastIndexOf("/");
            int end=pathandname.lastIndexOf(".");
            if(start!=-1 && end!=-1){
            return pathandname.substring(start+1,end);
            }else{
            return null;
            }
    
            }
    
    
    public void writePicture() {
            Picture picture = (Picture) pictures.get(presentPicture);
    
    
            byte[] pictureBytes = picture.getContent();
    
    
            Bitmap bitmap = BitmapFactory.decodeByteArray(pictureBytes, 0,
            pictureBytes.length);
    
    
            makePictureFile();
            presentPicture++;
    
    
            File myPicture = new File(picturePath);
    
    
            try {
    
    
            FileOutputStream outputPicture = new FileOutputStream(myPicture);
    
    
            outputPicture.write(pictureBytes);
    
    
            outputPicture.close();
            } catch (Exception e) {
            System.out.println("outputPicture Exception");
            }
    
    
            String imageString = "<img src=\"" + picturePath + "\"";
            imageString = imageString + ">";
    
    
            try {
            output.write(imageString.getBytes());
            } catch (Exception e) {
            System.out.println("output Exception");
            }
            }
    public void writeDOCXPicture(byte[] pictureBytes) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(pictureBytes, 0,
            pictureBytes.length);
            makePictureFile();
            this.presentPicture++;
            File myPicture = new File(this.picturePath);
            try {
            FileOutputStream outputPicture = new FileOutputStream(myPicture);
            outputPicture.write(pictureBytes);
            outputPicture.close();
            } catch (Exception e) {
            System.out.println("outputPicture Exception");
            }
            String imageString = "<img src=\"" + this.picturePath + "\"";
    
            imageString = imageString + ">";
            try {
            this.output.write(imageString.getBytes());
            } catch (Exception e) {
            System.out.println("output Exception");
            }
            }
    
    public void writeParagraphContent(Paragraph paragraph) {
            Paragraph p = paragraph;
            int pnumCharacterRuns = p.numCharacterRuns();
    
            for (int j = 0; j < pnumCharacterRuns; j++) {
    
            CharacterRun run = p.getCharacterRun(j);
    
            if (run.getPicOffset() == 0 || run.getPicOffset() >= 1000) {
            if (presentPicture < pictures.size()) {
            writePicture();
            }
            } else {
            try {
            String text = run.text();
            if (text.length() >= 2 && pnumCharacterRuns < 2) {
            output.write(text.getBytes());
            } else {
            int size = run.getFontSize();
            int color = run.getColor();
            String fontSizeBegin = "<font size=\""
            + decideSize(size) + "\">";
            String fontColorBegin = "<font color=\""
            + decideColor(color) + "\">";
            String fontEnd = "</font>";
            String boldBegin = "<b>";
            String boldEnd = "</b>";
            String islaBegin = "<i>";
            String islaEnd = "</i>";
    
            output.write(fontSizeBegin.getBytes());
            output.write(fontColorBegin.getBytes());
    
            if (run.isBold()) {
            output.write(boldBegin.getBytes());
            }
            if (run.isItalic()) {
            output.write(islaBegin.getBytes());
            }
    
            output.write(text.getBytes());
    
            if (run.isBold()) {
            output.write(boldEnd.getBytes());
            }
            if (run.isItalic()) {
            output.write(islaEnd.getBytes());
            }
            output.write(fontEnd.getBytes());
            output.write(fontEnd.getBytes());
            }
            } catch (Exception e) {
            System.out.println("Write File Exception");
            }
            }
            }
            }
    一些格式:

    public int decideSize(int size) {
    
            if (size >= 1 && size <= 8) {
            return 1;
            }
            if (size >= 9 && size <= 11) {
            return 2;
            }
            if (size >= 12 && size <= 14) {
            return 3;
            }
            if (size >= 15 && size <= 19) {
            return 4;
            }
            if (size >= 20 && size <= 29) {
            return 5;
            }
            if (size >= 30 && size <= 39) {
            return 6;
            }
            if (size >= 40) {
            return 7;
            }
            return 3;
            }
    
    private String decideColor(int a) {
            int color = a;
            switch (color) {
            case 1:
            return "#000000";
            case 2:
            return "#0000FF";
            case 3:
            case 4:
            return "#00FF00";
            case 5:
            case 6:
            return "#FF0000";
            case 7:
            return "#FFFF00";
            case 8:
            return "#FFFFFF";
            case 9:
            return "#CCCCCC";
            case 10:
            case 11:
            return "#00FF00";
            case 12:
            return "#080808";
            case 13:
            case 14:
            return "#FFFF00";
            case 15:
            return "#CCCCCC";
            case 16:
            return "#080808";
    default:
            return "#000000";
            }
            }

    好吧,大功告成,看看效果。

    我设置了个dialog式的activity来展现下,可以放大缩小:

    读取doc:


    读取docx:

                                                 

    读取xls和xlsx:


    代码demo已经上传:http://download.csdn.net/detail/bit_kaki/9676592 需要两积分。如果积分不够的可以私信我或者留言地址,我看到也会回复

     











    展开全文
  • 博主称这类excel模板为略复杂表头模板(蓝色部分为表头部分,蓝色前面几行是博主项目的基础样式,称为元数据),这类excel的表头多为2-3行,甚至于5/6行 ,具有合并层级关系,看似复杂,但只需要在我们以前的基础上...
  • POI-Excel解析Excel表单数据1、Excel表格解析公用接口2、Excel表格解析通用抽象类3、03版Excel解析4、07版Excel解析 ...针对不同版本Excel创建不同解析器去解析Excel表单有些复杂化了,其实完全可以将AbstractExcelP...
  • [图片说明](https://img-ask.csdn.net/upload/201711/08/1510105595_689027.png)如何解析这样的excel,excle表头中有数据库表名 和 中文信息 然后有字段信息,空行分开(可能多个) 再同样格式,再有一个。 ...
  • 前面几篇文章介绍了博主最近项目中对于复杂excel表头的解析,写得不好,感谢园友们的支持~~~ 今天再简单讲诉一下另一种“变异”EXCEL表头模板——矩阵表头模板的解析(博主感觉这种模板虽说怪异,但是偶尔也能...
  • 【摘要】本文介绍如何将各种结构 Excel 文件解析成结构化数据,如普通行式、复杂表头、自由格式、交叉表、主子表、大文件等,并用 esProc SPL 举例实现。请点击Excel 文件结构化解析示例了解详情本文将介绍如何...
  • JAVA程序猿经常选择使用POI或者HSSFWorkbook等第三方类库来实现,通常都要硬编码,如果碰到格式复杂的表格,解析工作量还会成倍增加,Java没有表格对象,总要利用集合加实体类去实现,导致代码冗长、不通用。...
  • Excel 文件导入关系数据库是数据分析业务中经常要做事情,但许多 Excel 文件格式并不...JAVA程序猿经常选择使用POI或者HSSFWorkbook等第三方类库来实现,通常都要硬编码,如果碰到格式复杂的表格,解析工作量...
  • C# 解析Excel

    千次阅读 2019-01-03 12:14:37
    分享一篇自己写的 解析Excel的代码 网上很多帖子都写的太复杂了,就自己重新整理了一份 支持读写 Microsoft.Office.Interop.Excel 这个是个DLL 直接百度下载就可以了。 添加进解决方案的引用 using Microsoft.Office...
  • 通过对之前java解析excel的研究,发现无法满足不了某些复杂格式excel的解析,例如 该格式的excel用之前的方法就无法解析,那么针对这种复杂格式的excel我们应如何解析呢? 分析问题 我们通过debug测试研究该复杂...
  • POI解析Excel

    千次阅读 2015-10-29 17:32:37
    最近做一个功能是上传Excel解析Excel,众所周知,excel文件有两个扩展名(xls,xlsx),是因为Microsoft Excel分两个大版本,2003以前和2007以后。 功能并不复杂,但做过程中却是遇到很多坎坷。 目前解析Excel...
  • 读写Excel的常用技术:(语言不重要,Python也可以) POI (效率高,操作复杂,支持功能多) http://poi.apache.org/ POI提供API给Java程序对Microsoft Office格式档案读写功能. HSSF(Horrible SpreadSheet Format...
  • 通过销售地图项目和目前的评分系统的项目都需要用到解析excel,并且每次因为excel中列名的不同和对应的实体类的不同,每一次都需要重新写一个解析excel的方法,代码之长很复杂也很麻烦写,每一次动辄就几十行代码,...
  • 本文介绍如何将各种结构 Excel 文件解析成结构化数据,如普通行式、复杂表头、自由格式、交叉表、主子表、大文件等,并用 esProc SPL 举例实现。请点击Excel 文件结构化解析示例了解详情 在数据分析业务中,...
  • 由于Java并没有表格对象,总要利用集合加实体类去实现(硬编码),如果碰到格式复杂的表格,解析难度大,工作量会成倍增加,代码不仅冗长、且很难通用。比如要处理这么个场景:数据库表Logistics有3个字段:Shippers、...
  • POIExcel文件导出 思路: 现在很多Excel导出都有Excel模板,直接将数据封装好,直接调用即可, 但是我们项目变动较大,所以我选择...-- poi 文件上传,解析excel--> <dependency> <groupId>org.apache.poi
  • 最近要做一个导入导出 Excel 功能,上一...整体感受就是,做简单场景 Excel 导入导出还可以,但是如果需要加一些复杂交互功能话,前后端交互就比较繁琐了,可能需要来来回回好几次请求(比如字段映射,预览,...
  • 之前使用poi读取,直接报错,使用excel 事件方式读取,还有不少bug,关键是程序写复杂。 解决方案 我们知道excel 文件实际上是一个压缩包来,我们将excel 直接改名为rar或zip文件。 我们可以将文件...
  • 【摘要】本文介绍如何将各种结构 Excel 文件解析成结构化数据,如普通行式、复杂表头、自由格式、交叉表、主子表、大文件等,并用 esProc SPL 举例实现。请点击Excel 文件结构化解析示例了解详情在数据分析业务中...
  • Poi方式解析excel

    2013-10-10 22:02:25
    最近项目需要实现几个excel导入导出功能、最开始用jxl、不过jxl不能解析07以上文档、感觉不是很方便、感觉apache官方API对微软文档支持还不错、便试着用了一下、比jxl稍微复杂了一点点、不过好在功能比较...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 214
精华内容 85
关键字:

复杂excel的解析