如何正确计算导入Excel的行数(POI/NPOI)

前言:

在一些具体的业务实现中经常要使用Excel作为数据的来源,或者导出一些Excel。
一般我们都是使用POI(Java)/NPOI(.Net)来读取或写入相关的数据。
这个月接手别人的模块,在模块中需要频繁的导入导出Excel操作,在给那些‘测试’对接时,经常出现导入失败的情况,非常烦人。
这大概率是POI/NPOI的行数和实际导入的Excel有效行数不一样造成的

问题再现

这里以下面的一个Excel为例
请添加图片描述
这个Excel没有改格式也没有加空格,它的行数统计如下

XSSFWorkbook book = new XSSFWorkbook(new FileInputStream("src/Test.xlsx"));
//结果为8,sheet最后的一行有数据行的行数(从0开始算)		
System.out.println(book.getSheetAt(0).getLastRowNum());
//结果为9,sheet实际有数据的总行数	
System.out.println(book.getSheetAt(0).getPhysicalNumberOfRows());

这里随便插入一行再运行便可再次测试
请添加图片描述

XSSFWorkbook book = new XSSFWorkbook(new FileInputStream("src/Test.xlsx"));
//结果为12		
System.out.println(book.getSheetAt(0).getLastRowNum());
//结果为10	
System.out.println(book.getSheetAt(0).getPhysicalNumberOfRows());

1.空格造成的行数错误

导入者不仔细造成的多余空格行通常是这种错误的原因。
模拟:我在黑框处添加了空格
请添加图片描述
这次会得到

XSSFWorkbook book = new XSSFWorkbook(new FileInputStream("src/Test.xlsx"));
//15		
System.out.println(book.getSheetAt(0).getLastRowNum());
//11		
System.out.println(book.getSheetAt(0).getPhysicalNumberOfRows());

这样,当在程序中使用判断行数的方法时便会出现偏差,导致异常及错误
像是

  • 获取没有值的单元格的值-------------------------------空指针
  • 获取一些空格的值进入Sql参数------------------------Sql语句错误

2.格式造成的行数错误

请注意,有些情况下,导入的Excel的Sheet中存在不同的格式,并不是所有的导入都是默认的通用格式,
请添加图片描述
当我选定一片区域改成别的格式的时候,POI判断的长度也会改变
请添加图片描述

SSFWorkbook book = new XSSFWorkbook(new FileInputStream("src/Test.xlsx"));
//18		
System.out.println(book.getSheetAt(0).getLastRowNum());
//19		
System.out.println(book.getSheetAt(0).getPhysicalNumberOfRows());

有些时候对某些行列改变格式,也会造成POI的行数错误。
(之前在工作中就有过经历,约定以文本的格式导入Excel,结果不知道什么原因,有人用文本格式拉了几千行,
DEBUG的时候看到NPOI的获取Sheet的行数上千就非常的懵逼)

结论:
故决定不用POI/NPO提供的获取行数的API,必须自己手动计算一下,不然保不齐对接的时候一堆奇奇怪怪的导入出错

手动计算行数

POI

手动计算Sheet的长度要做到一定正确也需要一定的规则
我们一般
默认导入Excel的Sheet里的数据不要有中断的空行,即Excel的数据行从首行(一般是列名)开始,一直连续
请添加图片描述
所以我们只需要判断单元格的值是否为Null或者是空格(多个空格)且一直连续了多少行,
下面给出测试代码

/***
 *  前言:如果你有自己常用的String处理方法,或者框架里的字符串工具,你完全可以不使用下面的流操作判断是否为空字符串
* 
 * @param sheet          表
 * @param StartNum       数据开始的行号(即除去你的表头占的行数,真正的数据从哪行开始的)
 * @param RequireCol_index  必要数据列的列号(导入Excel中任意一个不为空列的列号即可)
 * @return Excel的sheet的有效行数
 */
public static int GetRealRowNum(Sheet sheet,int StartNum,int RequireCol_index) {
		int Count = 0;

		   
		    //这里第一个条件可以判断单元格非空,第二个则利用流操作去判断是否其中所有的字符全是空字符或空格字符。 
			while(sheet.getRow(StartNum).getCell(RequireCol_index)!=null&&
					!ToList(sheet.getRow(StartNum).getCell(RequireCol_index).toString().toCharArray())
					.stream().allMatch((Character item)->{
						if(item.equals(' ')||item.toString().equals(""))
							return true;
						else
							return false;
					})
					)
			{
				//用Count计算有效长度
				StartNum++;Count++;
			}
		}catch (Exception e) {
			
		}
		return Count;
	}
	
	public  static List<Character> ToList(char[] charArray){
		List<Character> chars = new ArrayList<Character>(); 
		
		for(int i=0;i<charArray.length;i++)
			chars.add(charArray[i]);
		
		return chars;
	}

测试一下,
还是上面那张被修改了格式的Excel
请添加图片描述
在里面随机埋了写空格,并选中一块敌法更改格式,得到的结果如下

public static void main(String[] args) throws IOException {
		
		
	XSSFWorkbook book = new XSSFWorkbook(new FileInputStream("src/Test.xlsx"));
	//28
	System.out.println(book.getSheetAt(0).getLastRowNum());
	//24
	System.out.println(book.getSheetAt(0).getPhysicalNumberOfRows());
	//8
	System.out.println(GetRealRowNum(book.getSheetAt(0), 1, 0));
	
}

大多数情况下是可以用的,但实际的工作中肯定是使用字符串工具来判断是否为空格字符串或空字符串

//直接用字符串工具久非常的简单明了
while(sheet.getRow(StartNum).getCell(RequireCol_index)!=null&&
	!StringUtil.isBlank(sheet.getRow(StartNum).getCell(RequireCol_index).toString()))
{
	StartNum++;Count++;
}

结果也是上面一样。
注:(StringUtils/StringUtils有非常多的同名类,且方法也会各有不同。例子用到的是org.jsoup.internal.StringUtil)

NPOI

NPOI的使用方法也类似,

int start = 1, 
count_row = 0;
try
{
    
    while (sheet.GetRow(start).GetCell(0) != null && !string.IsNullOrWhiteSpace((sheet.GetRow(start).GetCell(0).ToString()))
   {
      count_row++;start++;
   }
}catch(Exception e)
{

}
return count_row ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗马苏丹默罕默德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值