-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
多行动态表头excel导入 #274
Comments
因为很难知道哪里是头哪里是数据的原因,所以多行表头建议二次封装,Row提供了类似jdbc的基础接口,可以通过下标获取单元格内容 |
可以考虑加入类似的参数。 row是Stream包裹所以可以使用filter做类似的处理,sheet.rows().filter(r -> r.getRowNum()>=2).map(this:toMap).collect(),在toMap方法里将row转map这样处理看上去也不会太乱 |
不过并不建议将数据转为Map,因为每一行都需要将表头作为key,1w行数据转Map就需要保存1w次表头,太浪费空间了。 |
转map浪费空间这个确实无解了,只是方便操作一下。通过列索引的方式,就是比较硬编码了。 |
有好的想法欢迎提交Pull Request |
最近没时间,加班状态中……等有时间了先研究研究文档格式 |
好用是话请给个Star并推荐给身边的朋友 |
从第一次看到eec,就已经Star了,现在是看到有用到导入导出的就说试试这个,哈哈^_^ |
每一行的列数不同是正常的,比例你的示例文件里有些人没有参与过考试或仅参与部分考试,这些行只能读到前几列。 所以每一行都有不同的列范围,不可以通过dimension来判断,你必须通过Row对象的 dimension是整个Worksheet的有效范围,这里有效包含文字,背景,字体,边框,格式化等一切excel有效数据,所以dimension一般可用于文件行数的大致判断,比如要限制不能超过1w行,此时就可以使用dimension而不需要读取完整个文件,另一个用途是可以用来判断是同步处理还是异步处理,你可以设置阈值比如1千行,当文件行数小于1行时同步处理否则另起线程异步处理。 |
特意看了下Row#to方法,确实是根据columns.length方法循环设置值的,那就是这边获取值的时候要做下判断了。 |
你能将测试代码和抛异常的堆栈信息贴一下吗?我还没找到到问题的原因
… 在 2022年8月1日,11:29,linmii ***@***.***> 写道:
特意看了下Row#to方法,确实是根据columns.length方法循环设置值的,那就是这边获取值的时候要做下判断了。
其实之前想的时,如果columnIndex >= columns.length,Row#get*方法不做rangeCheck校验,直接返回null。这样可能会能业务造成影响?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.
|
还是之前说的根据sheet.lastColumnIndex方法循环获取每一列的值会报错。 只是突然想到了Row#to方法,会不会也存在ArrayIndexOutOfBoundsException,但是看源码是使用row.columns.length循环取值赋值的,不会存在这个问题。 上次的回复只是说另外一个想法:Row#get**方法不做rangeCheck校验,如果columnIndex >= columns.length,直接返回null,而不是抛出ArrayIndexOutOfBoundsException异常,这样是否可行? |
如果可以的话还请将测试代码和抛异常的堆栈信息贴一下吧,ArrayIndexOutOfBoundsException我本地确实没有复现,但感觉应该是一个隐藏的BUG,所以还是想复现出来。 下面是范围判断的部分代码,目前仅判断了负数的情况,如果超过范围将返回一个未实例化的Cell,所以就算空Excel文件使用 /**
* Check the cell ranges,
*
* @param index the index
* @exception IndexOutOfBoundsException If the specified {@code index}
* argument is negative
*/
protected void rangeCheck(int index) {
if (index < 0)
throw new IndexOutOfBoundsException("Index: " + index + " is negative.");
}
/**
* Returns {@link Cell}
*
* @param i the position of cell
* @return the {@link Cell}
*/
protected Cell getCell(int i) {
rangeCheck(i);
return i < lc ? cells[i] : UNALLOCATED_CELL;
}
/**
* Search {@link Cell} by column name
*
* @param name the column name
* @return the {@link Cell}
*/
protected Cell getCell(String name) {
int i = hr.getIndex(name);
rangeCheck(i);
return i < lc ? cells[i] : UNALLOCATED_CELL;
} |
是我这边代码写错了,lastColumnIndex用了<=,导致报这个错误 val headRows = 2
val result = mutableListOf<Map<String, String>>()
ExcelReader.read(Path("C:/Users/user/Desktop/测试.xlsx"))
.use {
val sheet = it.sheet(0)
val lastColumnIndex = sheet.dimension.lastColumn.toInt()
val headColumnArray: Array<Array<String?>> =
Array(headRows) { arrayOfNulls(lastColumnIndex) }
val headArray = arrayOfNulls<String>(lastColumnIndex)
sheet.reset()
sheet.rows()
.forEach { row ->
if (row.rowNum <= headRows) {
(0 until lastColumnIndex).forEach { index ->
headColumnArray[row.rowNum - 1][index] =
if (index > row.lastColumnIndex)
headColumnArray[row.rowNum - 1][index - 1]
else
row.getString(index)
?: if (row.rowNum== headRows) headColumnArray[row.rowNum - 1][index - 1] else ""
}
if (row.rowNum == headRows) {
(0 until lastColumnIndex).forEach { index ->
headArray[index] =
(0 until headRows).map { r -> headColumnArray[r][index] }
.joinToString()
}
}
} else {
val map = mutableMapOf<String, String>()
(0 until lastColumnIndex).forEach { index ->
map[headArray[index]!!] =
if (index > row.lastColumnIndex) ""
else row.getString(index)
}
}
}
} |
fix#306 分支增加指定表头的位置的方法,可以通过sheet#header(from, to) 指定多行表头,对于上面给的多行表头特别合适 尝鲜的话可以clone并切换到分支fix#306并使用
多行表头使用(:)冒号拼接,上面代码表头输出如下
|
Row header = sheet.header(1, 2).getHeader(); Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 26 out of bounds for length 26
at org.ttzero.excel.reader.HeaderRow.mergeCellsIfNull(HeaderRow.java:751)
at org.ttzero.excel.reader.HeaderRow.with(HeaderRow.java:118)
at org.ttzero.excel.reader.XMLSheet.getHeader(XMLSheet.java:309)
at org.ttzero.excel.reader.XMLSheet.getHeader(XMLSheet.java:272) |
XMLSheet#getHeader(int, int) 292行设置 |
HeaderRow#with方法有传入合并单元格信息,现在的表头是什么样的,最好能给个截图看下,这个分支还在开发测试样本不够 |
我是在想是不是在 |
是的,外部提前处理更合理 |
已更新,请pull新代码尝试 仔细看了一下这里不能缩小lc的值相反要扩大,不然与第二行对应不上,缩小后最后一个头只有"考试时长"不会有"2021-07-10:考试时长" |
下面的代码会报错,还是之前的错误: 在获取Rows[]的时候,lc应该取指定表头行中的最大列,我提交了PR,你看下有没有可以优化的地方。 HeaderRow增加了getNames()方法,可以遍历表头获取数据。 Row header = sheet.header(1, 2).getHeader();
System.out.println(header); Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 26 out of bounds for length 26
at org.ttzero.excel.reader.HeaderRow.mergeCellsIfNull(HeaderRow.java:751)
at org.ttzero.excel.reader.HeaderRow.with(HeaderRow.java:118)
at org.ttzero.excel.reader.XMLSheet.getHeader(XMLSheet.java:309)
at org.ttzero.excel.reader.XMLSheet.getHeader(XMLSheet.java:272) |
感谢你的PR,稍后会review 你可以尝试拉取最新的fix#306分支代码,看看是否满足你的场景。 |
刚刚试了下,fix306最新的代码确实已经处理了异常,可以正常使用,应该是我之前拉的不是最新的代码,看了下提交日志,你是在HeaderRow#mergeCellsIfNull方法进行的处理,我把这部分逻辑提前到XMLSheet#getHeader中了,你看看哪种方式更好。 |
对于用ListMapSheet导出的多行动态表头excel,是否有方便的方法进行导入呢?
看目录导入的方法,获取到sheet后,rows返回第1行开始的数据,dataRows返回第2行开始的数据,都不太好处理数据。
希望能像导出的时候使用List一样,导入的时候也可以转成Map。
以下图为例,Map中的key分别姓名、二级机构、...、2021-07-01得分、2021-07-01考试时长、2021-07-02得分、2021-07-02考试时长...
The text was updated successfully, but these errors were encountered: