groovy 不使用VBA如何获取工作表的使用范围?

mrphzbgm  于 2022-11-01  发布在  其他
关注(0)|答案(2)|浏览(225)

我使用groovy脚本来处理excel文件。我使用POI API来操作这些文件。但是在documentation中没有方法或对象来帮助我找到一种方法来获得工作表的使用范围。* 我试图使用getLastRowNum()getPhysicalNumberOfRows()等方法来自己计算它,但是它们都没有很好地工作,因为它们在遇到空行时会停止计数。有时Excel文件可以有空行,这些空行后,他们可以填充行,但这些方法只是停止时,他们只是满足一个空行.所以这些功能将不会帮助我达到我的目标.*
所以我尝试了另一个解决方案。我想通过使用createName()方法在工作簿中创建一个命名区域,然后使用一个公式创建一个命名区域,该公式返回实际工作表中使用的区域。但我不知道如何创建,我搜索了很多,找到的都是关于VBA的。我不想使用它,因为在命名的范围公式中,我们不能使用VBA。我发现了一个函数调用GET.WORKBOOK,我认为这可能是一个很好的起点,以寻找答案,我的问题。这个函数返回工作簿的工作表名称列表。我的问题和这个结果之间没有联系,但我认为GET对象可以包含更多的方法,如GET.WORKSHEET。这是非常推测的,但我认为不仅仅是GET.WORKBOOK。(* 如果你有任何关于这个的信息,即使它不能解决我的问题,请把这个放在评论里,我真的对这个GET函数很感兴趣。*)
NB:如果你能找到一个解决我的问题的方法,我也会很高兴的。我不记得这种类型的解决方案,因为我在这个方向上搜索了很多,但我没有找到任何帮助我的东西。
我添加java标签是因为groovy和java非常接近。我认为有人可以在java中找到解决这个问题的方法,在groovy中也可以这样做。
NB3:我想要一个像A1:B2这样的单元格引用来指定使用的范围
NB4:我重新测试了getLastRowNum()方法,它运行得很好,我在代码中犯了一些错误,这就是它运行得不好的原因。现在我的新问题是,当我使用这个方法时,我无法使用getCell方法访问空的单元格。下面是我的代码:

import org.apache.poi.ss.usermodel.WorkbookFactory; 

wb = WorkbookFactory.create(new File("./webapps/etlserver/data/files/test_ws.xlsx"));

def getUsedRangeByIndex(file_path,ind_ws){
    wb = WorkbookFactory.create(new File(file_path));
    max_col = 0;
    for(int i = 0 ; i < wb.getSheetAt(ind_ws).getLastRowNum() ; i++){
        LOG.info(i.toString())
        if(wb.getSheetAt(ind_ws).getRow(i) != null && wb.getSheetAt(ind_ws).getRow(i).getLastCellNum() > max_col){
              max_col = wb.getSheetAt(ind_ws).getRow(i).getLastCellNum();
        }
    }

    return "A1:" + wb.getSheetAt(ind_ws).getRow(wb.getSheetAt(ind_ws).getLastRowNum()).getCell(max_col, RETURN_NULL_AND_BLANK).getReference()
}

LOG.info(getUsedRangeByIndex("./webapps/etlserver/data/files/test_ws.xlsx",0))

我知道我必须用一些计算第一个使用的单元格的代码来改进它,但现在我将考虑A1作为第一个使用的单元格。

qlfbtfca

qlfbtfca1#

如果工作表的使用范围定义如下:...
使用的范围是从左上角第一个使用的单元格到右下角最后一个使用的单元格的单元格范围。
...并且使用的Apache POI版本是当前版本之一(我使用apache poi 5.2.2),则获取使用范围的最简单方法是使用以下方法:
Sheet.getFirstRowNum和Sheet.getLastRowNum,用于获取工作表中第一个使用的行和最后一个使用的行。如果其中一个返回-1,则工作表不包含任何行,因此没有使用的范围。
然后,在第一个使用的行和最后一个使用的行之间的所有行上循环,并获取Row.getFirstCellNum和Row. getLastCellNum。请注意Row.getLastCellNum的API文档:获取此行中包含的最后一个单元格的索引PLUS ONE。如果在该行中找到的第一列小于在找到第一列之前找到的第一列,则此列为新的第一列。如果在该行中找到的最后一列大于在找到最后一列之前找到的最后一列,则此列为新的最后一列。
然后我们有第一个使用的行,最后一个使用的行,最左边使用的列和最右边使用的列。这就是使用的范围。
完整示例:

import java.io.FileInputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

class ExcelGetSheetUsedRange {

 /**
  * Simplest method to get the used range from a sheet.
  *
  * @param sheet The sheet to get the used range from.
  + @return CellRangeAddress representing the used range or null for an empty sheet.
  */    
 static CellRangeAddress getUsedRange(Sheet sheet) {
  int firstRow = sheet.getFirstRowNum();
  if (firstRow == -1) return null;
  int lastRow = sheet.getLastRowNum();
  if (lastRow == -1) return null;
  int firstCol = Integer.MAX_VALUE;
  int lastCol = -1;
  for (int r = firstRow; r <= lastRow; r++) {
   Row row = sheet.getRow(r);
   if (row != null) {
    int thisRowFirstCol = row.getFirstCellNum();
    int thisRowLastCol = row.getLastCellNum()-1; // see API doc Row.getLastCellNum : Gets the index of the last cell contained in this row PLUS ONE.
    if (thisRowFirstCol < firstCol) firstCol = thisRowFirstCol;
    if (thisRowLastCol > lastCol) lastCol = thisRowLastCol;
   }   
  }
  if (firstCol == Integer.MAX_VALUE) return null;
  if (lastCol == -1) return null;
  return new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
 }  

 public static void main(String[] args) throws Exception {
  //Workbook workbook = WorkbookFactory.create(new FileInputStream("./template.xls"));  
  Workbook workbook = WorkbookFactory.create(new FileInputStream("./template.xlsx"));   
  Sheet sheet = workbook.getSheetAt(0);
  CellRangeAddress usedRange = getUsedRange(sheet);
  System.out.println(usedRange);  
 }
}

如Sheet.getLastRowNum的API文档中所述:
注意:之前有内容但后来被设置为空的行可能仍被Excel和Apache POI计为行...
但这是Excel的一个问题,当通过Worksheet.UsedRange property获取使用的范围时也可能发生。

zpjtge22

zpjtge222#

Axel Richter的解决方案是完美的。但是这里有一个预构建代码,你可以直接插入到jedox作业中,让它正常工作。这是一种从java到groovy的转换。下面是代码:

import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;

wb = WorkbookFactory.create(new File("./webapps/etlserver/data/files/test_ws.xlsx")); 
sheet = wb.getSheetAt(0);

def getUsedRange(sheet) {
    firstRow = sheet.getFirstRowNum();
    if (firstRow == -1) return null;
    lastRow = sheet.getLastRowNum();
    if (lastRow == -1) return null;
    firstCol = Integer.MAX_VALUE;
    lastCol = -1;
    for (int r = firstRow; r <= lastRow; r++) {
     row = sheet.getRow(r);
     if (row != null) {
        thisRowFirstCol = row.getFirstCellNum();
        thisRowLastCol = row.getLastCellNum()-1;
        if (thisRowFirstCol < firstCol) firstCol = thisRowFirstCol;
        if (thisRowLastCol > lastCol) lastCol = thisRowLastCol;
     }   
    }
    if (firstCol == Integer.MAX_VALUE) return null;
    if (lastCol == -1) return null;

    return (new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)).formatAsString();
}   

LOG.info(getUsedRange(sheet));

相关问题