精华内容
下载资源
问答
  • 关于Excel数据处理,很多同学可能使用过Pyhton的pandas模块,用它可以轻松地读取和转换Excel数据。但是实际中Excel表格结构可能比较杂乱,数据会分散不同的工作表中,而且在表格中分布很乱,这种情况下啊直接使用...

    关于Excel数据处理,很多同学可能使用过Pyhton的pandas模块,用它可以轻松地读取和转换Excel数据。但是实际中Excel表格结构可能比较杂乱,数据会分散不同的工作表中,而且在表格中分布很乱,这种情况下啊直接使用pandas就会非常吃力。本文虫虫给大家介绍使用pandas和openpyxl读取这样的数据的方法。

    eb9427c51280e2793fc87d66ee8337ac.png-wh_651x-s_2121381490.png

    问题缘起

    pandas read_excel函数在读取Excel工作表方面做得很好。但是,如果数据不是从头开始,不是从单元格A1开始的连续表格,则结果会不是很好。比如下面一个销售表,使用read_excel读取:

    0da85dd4b795b5409a1fc2a1b8159ce1.png-wh_600x-s_3586092529.png

    读取的结果如下所示:

    5f4a06ea43bd93114b7ddb4641e84444.png-wh_600x-s_3132199054.png

    结果中标题表头变成了Unnamed,而且还会额外增加很多职位NaN列,字段为空的列的值也会被转换为NaN,这显然不是我们所期望的。

    header和usecols参数

    对这样的非标准格式的表格,我们可以使用read_excel()的header和usecols参数来控制选择的需要读取的列。

    importpandasaspd

    frompathlibimportPath

    src_file='sales.xlsx'

    2a1113a2894b92ac85079a1a14d7520d.png

    结果的DataFrame包含了我们期望的数据。

    代码中使用header和usecols参数设定了用于显示标题的列和需要读取的字段:

    header参数为一个整数,从0开始索引,其为选择的行,比如1表示Excel中的第2行。

    usecols参数设定选择的Excel列范围范围(A-…),例如,B:F表示读取B到F列。

    在某些情况下,可能希望将列定义为数字列表。比如,可以定义整数列数:

    df=pd.read_excel(src_file,header=1,usecols=[1,2,3,4,5])

    这对对大型数据集(例如,每3列或仅偶数列)要遵循一定的数字模式,则这个参数方法会很有用。

    usecols还可以设定从列名列表读取。比如上面的例子也可以这样写:

    df=pd.read_excel(

    src_file,

    header=1,

    usecols=['item_type','orderid','orderdate','state','priority'])

    列顺序支持自由选择,这种命名列列表的方式实际中很有用。

    usecols支持一个回调函数column_check,可通过该函数对数据进行处理。

    下面是一个简单的示例:

    defcolumn_check(x):

    if'unnamed'inx.lower():

    returnFalse

    if'priority'inx.lower():

    returnFalse

    if'order'inx.lower():

    returnTrue

    returnTrue

    df=pd.read_excel(src_file,header=1,usecols=column_check)

    column_check按名称解析每列,每列通过定义True或False,来选择是否读取。

    usecols也可以使用lambda表达式。下面的示例中定义的需要显示的字段列表。为了进行比较,通过将名称转换为小写来规范化。

    cols_to_use=['item_type','orderid','orderdate','state','priority']

    df=pd.read_excel(src_file,

    header=1,

    usecols=lambdax:x.lower()incols_to_use)

    回调函数为我们提供了许多灵活性,可以处理Excel文件的实际混乱情况。

    关于read_exce函数更多参数可以查看官方文档,下面是一个总结表格:

    58dd6f878561215518cddfb006e3b9aa.png-wh_600x-s_3695290640.png

    结合openpyxl

    在某些情况下,数据甚至可能在Excel中变得更加复杂。在下面示例中,我们有一个ship_cost要读取的表。如果必须使用这样的文件,那么只用pandas函数和选项也很难做到。在这种情况下,可以直接使用openpyxl解析文件并将数据转换为pandas DataFrame。比如要读取下面示例的数据:

    ab19243a11e1ea6f91d00470026b12a3.png-wh_600x-s_1105895039.png

    fromopenpyxlimportload_workbook

    importpandasaspd

    frompathlibimportPath

    src_file='sales1.xlsx'

    加载整个工作簿:

    cc=load_workbook(filename=src_file)

    查看所有工作表:

    cc.sheetnames

    ['sales', 'shipping_rates']

    要访问特定的工作表:

    sheet=cc['shipping_rates']

    要查看所有命名表的列表:

    sheet.tables.keys()

    dict_keys(['ship_cost'])

    该键对应于Excel中分配给表的名称。这样就可以设定要读取的Excel范围:

    lookup_table=sheet.tables['ship_cost']

    lookup_table.ref

    'C8:E16'

    这样就获得了要加载的数据范围。最后将其转换为pandas DataFrame即可。遍历每一行并转换为DataFrame:

    data=sheet[lookup_table.ref]

    rows_list=[]

    forrowindata:

    cols=[]

    forcolinrow:

    cols.append(col.value)

    rows_list.append(cols)

    df=pd.DataFrame(data=rows_list[1:],index=None,columns=rows_list[0])

    结果数据框:

    bf1c1be100632ad26dfd4f4b9f2bfeff.png

    总结

    在理想情况下,使用的数据将采用简单一致的格式。在本文中,我们介绍了在Pandas下通过参数轻松删除行和列以使其格式更加合理。尤其是结合openpyxl的情况下可以让我们读取Excel数据更加灵活,可以处理比较复杂的表格数据。

    展开全文
  • 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;
    	}
    

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

    总结

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

    展开全文
  • Java使用POI解析复杂Excel思维模式

    千次阅读 2016-11-24 19:17:03
    Java使用POI解析复杂Excel思维模式

    功能需求:

       如图这样的Excel,要求解析出来,且存储到数据库中能够呈现出层级关系。且最后一级要有自己的几何非几何属性。

    需求分析:

           1.首先我们发现这个Excel有这样一个规律,项目、IFD、是否标准这两个大类是样子是一一对应的,也就是说当我解析第一列的值、解析第五列的值、第十一列的值得函数可以是一样,同样第二列、第六列、第十二列也是可以一样的。。。

            2.我们发现只有当Excel类型表示其没有最后一列时,才可以对应其几何信息和非几何信息。

    程序分析:

           1. Java中导出Excel,有两种方式,POI和JXL。优缺点就不用讲了。这里只阐述Java使用POI解析Excel

            2.程序中涉及到的POI中读取特定单元格的值,Excel读取合并单元格的值

           

        /**   
        * 获取合并单元格的值   
        * @param sheet   
        * @param row   
        * @param column   
        * @return   
        */    
        public static String getMergedRegionValueAndInfo(Sheet sheet ,int row , int column){    
        	String MergedVal="";
        	String MergedInfo="";
            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);    
                        MergedVal=getCellValue(fCell);
                        MergedInfo=String.valueOf(firstColumn)+","+String.valueOf(firstRow)+","+String.valueOf(lastColumn)+","+String.valueOf(lastRow);
                        return MergedVal+"&"+MergedInfo ;    
                    }    
                }    
            }    
            return null ;    
        } 
        
        /**  
        * 判断合并了行  
        * @param sheet  
        * @param row  行
        * @param column  列
        * @return  
        */  
        private boolean isMergedRow(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();  // 0 0   3 1
        		if(row == firstRow && row == lastRow){  
        			if(column >= firstColumn && column <= lastColumn){  
        				return true;  
        			}  
        		}  
        	}  
        	return false;  
        } 
        
        /**  行合并
        * 判断单元格向行方向合并
        * 判断指定的单元格是否是合并单元格  
        * @param sheet   
        * @param row 行下标  
        * @param column 列下标  
        * @return  
        */  
        public static boolean 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 true;  
        			}  
        		}  
        	}  
        	return false;  
        } 
        ---读取特定单元格的值

        

        public static String getCellVal(XSSFSheet sheet,int rowNum,int columnNum){
        	row=sheet.getRow(rowNum);
        	Cell cell=row.getCell(columnNum);
        	return getCellValue(cell);
        }
    
     /**   
        * 获取单元格的值   
        * @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){   //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());    
            }else if(cell.getCellType() == Cell.CELL_TYPE_BLANK || cell.getCellType()==Cell.CELL_TYPE_ERROR){    //空值/故障
            	return "";    
        	}else{
        		return "";
        	}    
        }  
        这个POI解析最基础的就是使用这两个方法。那么开始我们的分析

       1.程序开始解析第一列,并适时解析第五列、第十一列。然后按照他存储起来,是一条记录

       2.程序开始开始解析第二列时。这个时候就需要寻找他的父亲。

            思维一:我们通过IFD读取第五列的IFD给其第六列的数据定位其父亲的唯一性

            思维二:我们在数据中记录其父亲的所在行、列的二维坐标加上sheet的名称来实现父亲的唯一性

    以上两种思维方式都对。但是呢?有缺陷,第一IFD是一串数字,数字编写上人为约定很有可能存在重复,那么你在寻找其父亲就没法做到唯一性。那么使用第二种?首先前提是,作为程序的编码者,要考虑用户为啥要使用Excel导入。因为客户不想麻烦,所以很有可能复制一个Excel改一改里面的某些内容,这个时候我们做到唯一性又加重了负担。

          从上述的两个思维来看,我们只有在当前导入的Excel中,确定了这个父亲的唯一性。而用户更换了下一个Excel后,他的唯一性任然存在。

          那么?Java中有什么方法可以实现定位到当前excel的父亲和儿子呢?

         MAP

         是的,我们交叉使用在第一列和第二列使用两个map,来记录其父子关系。第一个map的key是其行,value是他的值。第二个map也同样。当我们循环是,将其每一个行的值,和行号都存储,那么在儿子那一列时,我们就可以去父亲的map中用当前的key去取值。

    ---------------------------------------------------------------

        上面我们只是找到了其父子关系,那么作为层级关系的最后一级,需要给其赋值几何和非几何属性呢?

       这个逻辑灰常简单。就是确定其为最后一级

        情况一:这个Excel总共就只有4级,而第四列的任然有值存在,那么他就是最后一级

       情况二:我们以第二列的第五行为列。当for循环到这里时,发现其没有值,那么就要去寻找这一行的前一列是否有值,从而判断他是否为最后一列

       情况三:在情况的二的基础上的对立面。如果其有值,这个时候就要判断这一行的后一列是否有值,来判断其是否为最后一列

    -----------------------------------------------升华篇

       我们在上诉的分析中,发现对于我们在寻找父子关系列时,使用了两个Map,我们可以假想其为奇偶map,这样对于父子判断就可以简化程序。

       还有分析Excel的列关系,我们发现他是3*n+2的数据几何关系。

        基于上诉的表达,我们就完全可以不怕用户的Excel变化。无论多少层级关系,我们都是剑在手。


        




    展开全文
  • java后台对Excel解析

    2019-04-15 12:27:34
    java后台对Excel解析
  • 最近接到一个需求,需要把一份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 "完成";
    }
    
    展开全文
  • 我们在第三篇文章中谈到了那些非常反人类的excel模板,博主为了养家糊口,也玩命做出了相应的解析方法... 我们先来看看第一类复杂表头: ...... 博主称这类excel模板为略复杂表头模板(蓝色部分为表头...
  • Python Excel解析

    万次阅读 2015-10-31 21:27:46
    Python解析Excel时需要安装两个包,分别是xlrd(读excel)和xlwt(写excel),安装方法如下:pip install xlrd pip install xlwt 读取Excel表读取excel前需要先引入该模块(import xlrd)。但是需要注意的是,用xlrd...
  • [图片说明](https://img-ask.csdn.net/upload/201711/08/1510105595_689027.png)如何解析这样的excel,excle表头中有数据库表名 和 中文信息 然后有字段的信息,空行分开(可能多个) 再同样的格式,再有一个。 ...
  • 《POI解析复杂Excel

    千次阅读 2014-04-29 19:26:02
    + "/page/readExcel/sale.xls"; try { HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream( excelFileName)); // 获整个Excel for (int sheetIndex = 0; sheetIndex (); sheetIndex++...
  • 复杂格式不规范excel 文件解析

    千次阅读 2018-05-30 15:32:47
     * 解析excel  */  public class ExcelFileParser {     public static Workbook getWb(String path) {   try {   return WorkbookFactory.create(new File(path));   } catch (Exception e) {   ...
  • excel 模板如下 如图,一张excel 里有多个sheet,一个sheet中有一个表和多个续表, 如何解析这种excel,然后 将数据加入上面的数据库表中。可能每个sheet中表的行数会有变化,最后一张续表的列数不固定,其余列数...
  • 折腾:期间,需要去用python去读取和解析一个excel文件,并读取其中的内容,包括包括多个sheet,以及每个sheet中行row和列column的单元格cell的值:crifan python excel xlsxpython read excel ...
  • Excel解析工具easyexcel全面探索

    千次阅读 2019-10-24 17:39:00
    1. Excel解析工具easyexcel全面探索 1.1. 简介 之前我们想到Excel解析一般是使用POI,但POI存在一个严重的问题,就是非常消耗内存。所以阿里人员对它进行了重写从而诞生了easyexcel,它解决了过于消耗内存问题,也对...
  • 主要介绍了Java通过反射将 Excel 解析成对象集合实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 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包,代码如
  • C# 解析Excel

    千次阅读 2019-01-03 12:14:37
    分享一篇自己写的 解析Excel的代码 网上很多帖子都写的太复杂了,就自己重新整理了一份 支持读写 Microsoft.Office.Interop.Excel 这个是个DLL 直接百度下载就可以了。 添加进解决方案的引用 using Microsoft.Office...
  • POI-Excel解析Excel表单数据1、Excel表格解析公用接口2、Excel表格解析通用抽象类3、03版Excel解析4、07版Excel解析 注意 接口中public Object parseCell(Cell cell)方法需要自定义实现,这个方法是整个表单解析的...
  • Excel解析的几种实现方式

    千次阅读 2020-08-31 00:44:56
    文章目录Java读写Excel的方法POIJXLFastExcel读写PDFJXL的使用写Excel文档读取ExcelPOI使用写入Excel读取Excel创建高版本的Excel Java读写Excel的方法 有三种方式: POI JXL FASTEXCEL POI 是Apache软件基金会的...
  • NPOI.DLL 复杂Excel 生成Excel 读取Excel NPOI实例代码
  • Java 读取excel解析合并单元格

    千次阅读 2019-11-07 13:49:35
    解析这个excel 空格填写e ,单元格合并的拆分后填写合并前的值 id 啊 哦 额 1 2 2 3 2 e e 3 3 4 4 3 4 4 4 3 5 0 0 2019-09-01 code 依赖 <dependency> <groupId>org.apache.poi</...
  • Excel存储格式 POI表格解析 参考:https://poi.apache.org/components/spreadsheet/ 多线程读取 EasyExcel Hutool Excel工具
  • Freemarker导出复杂Excel图文教程

    千次阅读 2020-04-20 13:42:45
    简介 ...可是如果出现合并单元格、合并行的复杂Excel导出时,Freemarker的模板的插值也会变得复杂,但还是要比poi简单的多,用过Freemarker后,只要Freemarker能做到的,再也不想用poi导出Excel了。...
  • POI解析Excel

    千次阅读 2015-10-29 17:32:37
    最近做的一个功能是上传Excel解析Excel,众所周知,excel文件有两个扩展名(xls,xlsx),是因为Microsoft Excel分两个大版本,2003以前和2007以后。 功能并不复杂,但做的过程中却是遇到很多坎坷。 目前解析Excel...
  • 由于Java并没有表格对象,总要利用集合加实体类去实现(硬编码),如果碰到格式复杂的表格,解析难度大,工作量会成倍增加,代码不仅冗长、且很难通用。 比如要处理这么个场景:数据库表Logistics有3个字段:Shippers...
  • I would like to put a formula to an Excel cell:write(rownr,colnr,xlwt.Formula("ROUND(SUM('Hungarian word'.G%d:'Hungarian word'!G%d);0)" % (intval[0], intval[1]))(Note: the 'Hungarian word' is more wor...
  • 导入复杂excel

    千次阅读 2019-03-01 15:55:21
    // 解析excel,获取上传的数据 List<TaleiArchive> list=new ArrayList(); for(int i=0;i;i++){ list = readExcel.getExcelTaleiInfo(files[i]); } logger.trace("list"+list); Map, Object> map2 = new ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,129
精华内容 6,451
关键字:

复杂excel的解析