【问题标题】:Removing a row from an Excel sheet with Apache POI HSSF使用 Apache POI HSSF 从 Excel 工作表中删除一行
【发布时间】:2009-12-02 18:45:13
【问题描述】:

我正在使用 Apache POi HSSF 库将信息导入我的应用程序。问题是文件有一些额外/空行需要在解析之前先删除。

没有HSSFSheet.removeRow( int rowNum ) 方法。只有removeRow( HSSFRow row )。问题在于无法删除空行。例如:

sheet.removeRow( sheet.getRow(rowNum) );

在空行上给出 NullPointerException,因为 getRow() 返回 null。 此外,正如我在论坛上看到的那样,removeRow() 只会删除单元格内容,但该行仍然作为空行存在。

有没有一种方法可以在不创建没有我要删除的行的全新工作表的情况下删除行(是否为空)?

【问题讨论】:

    标签: java apache excel row apache-poi


    【解决方案1】:
     /**
     * Remove a row by its index
     * @param sheet a Excel sheet
     * @param rowIndex a 0 based index of removing row
     */
    public static void removeRow(HSSFSheet sheet, int rowIndex) {
        int lastRowNum=sheet.getLastRowNum();
        if(rowIndex>=0&&rowIndex<lastRowNum){
            sheet.shiftRows(rowIndex+1,lastRowNum, -1);
        }
        if(rowIndex==lastRowNum){
            HSSFRow removingRow=sheet.getRow(rowIndex);
            if(removingRow!=null){
                sheet.removeRow(removingRow);
            }
        }
    }
    

    【讨论】:

    • 这个解决方案在多行删除的情况下不起作用。
    • @gospodin - 在循环中运行内部代码,不要忘记在每次删除行时将 rowIndex 计数器减 1。
    • 当前 POI 中存在一个错误,当在包含公共单元格的范围上多次使用此函数时,将抛出 >org.apache.xmlbeans.impl.values.XmlValueDisconnectedExceptionbz.apache.org/bugzilla/show_bug.cgi?id=59733跨度>
    • 请在你的 if 语句中添加一些空格,没有任何空格很难阅读。无论如何,感谢您的回答。
    • 在某些情况下我得到:java.lang.RuntimeException: CountryRecord not found。在此处报告bz.apache.org/bugzilla/show_bug.cgi?id=55505,并修复了 Excel 中重新保存的评论。但是,该记录不会被删除。是否有可靠的非基于文件的解决方案。
    【解决方案2】:

    我知道,这是一个 3 年前的问题,但我最近不得不解决同样的问题,而且我必须用 C# 来解决。这是我在 NPOI 中使用的函数,.Net 4.0

        public static void DeleteRow(this ISheet sheet, IRow row)
        {
            sheet.RemoveRow(row);   // this only deletes all the cell values
    
            int rowIndex = row.RowNum;
    
            int lastRowNum = sheet.LastRowNum;
    
            if (rowIndex >= 0 && rowIndex < lastRowNum)
            {
                sheet.ShiftRows(rowIndex + 1, lastRowNum, -1);
            }
        }
    

    【讨论】:

      【解决方案3】:

      类似

      int newrownum=0;
      for (int i=0; i<=sheet.getLastRowNum(); i++) {
        HSSFRow row=sheet.getRow(i);
        if (row) row.setRowNum(newrownum++);
      }
      

      应该可以解决问题。

      【讨论】:

        【解决方案4】:

        HSSFRow 有一个名为setRowNum(int rowIndex) 的方法。

        当您必须“删除”一行时,将该索引放入List。然后,当您到达下一行非空时,您从该列表中获取一个索引并将其设置为调用setRowNum(),然后从该列表中删除该索引。 (或者你可以使用队列)

        【讨论】:

          【解决方案5】:

          我的特殊情况(对我有用):

              //Various times to delete all the rows without units
              for (int j=0;j<7;j++) {
                //Follow all the rows to delete lines without units (and look for the TOTAL row)
                for (int i=1;i<sheet.getLastRowNum();i++) {
                  //Starting on the 2nd row, ignoring first one
                  row = sheet.getRow(i);
                  cell = row.getCell(garMACode);
                  if (cell != null) 
                  {
                    //Ignore empty rows (they have a "." on first column)
                    if (cell.getStringCellValue().compareTo(".") != 0) {  
                      if (cell.getStringCellValue().compareTo("TOTAL") == 0) {
                        cell = row.getCell(garMAUnits+1);
                        cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
                        cell.setCellFormula("SUM(BB1" + ":BB" + (i - 1) + ")");
                      } else {
                        cell = row.getCell(garMAUnits);
                        if (cell != null) {
                          int valor = (int)(cell.getNumericCellValue());
                          if (valor == 0 ) {
                            //sheet.removeRow(row);
                            removeRow(sheet,i);
                          }
                        }
                      }
                    }
                  }
                }
              }
          

          【讨论】:

            【解决方案6】:

            此答案是对 AndreAY 答案的扩展,为您提供删除行的完整功能。

            public boolean deleteRow(String sheetName, String excelPath, int rowNo) throws IOException {
            
                XSSFWorkbook workbook = null;
                XSSFSheet sheet = null;
            
                try {
                    FileInputStream file = new FileInputStream(new File(excelPath));
                    workbook = new XSSFWorkbook(file);
                    sheet = workbook.getSheet(sheetName);
                    if (sheet == null) {
                        return false;
                    }
                    int lastRowNum = sheet.getLastRowNum();
                    if (rowNo >= 0 && rowNo < lastRowNum) {
                        sheet.shiftRows(rowNo + 1, lastRowNum, -1);
                    }
                    if (rowNo == lastRowNum) {
                        XSSFRow removingRow=sheet.getRow(rowNo);
                        if(removingRow != null) {
                            sheet.removeRow(removingRow);
                        }
                    }
                    file.close();
                    FileOutputStream outFile = new FileOutputStream(new File(excelPath));
                    workbook.write(outFile);
                    outFile.close();
            
            
                } catch(Exception e) {
                    throw e;
                } finally {
                    if(workbook != null)
                        workbook.close();
                }
                return false;
            }
            

            【讨论】:

            • 您保存文件的方法如何适应通过 url 访问文件的情况,例如 InputStream file = new URL("http://docker:[portNumber]/fileName.xlsx").openStream();
            【解决方案7】:

            我正试图深入了解我一两年前与 POI 相关的经验,但我的第一个问题是:为什么在解析之前需要删除行?为什么不直接从sheet.getRow(rowNum) 调用中捕获 null 结果并继续前进?

            【讨论】:

            • 因为我已经为 Excel 文件制作了一个解析器,这些文件被格式化为一个简单的表格(第一行的列名和下面的数据),如果有空行,我需要警告用户。另外,我现在要导入的文件来自另一个应用程序,并且有很多额外的行(空或非空)只是为了使文件看起来更好!
            • 好吧——不过,我只想说,如果你将现有的解析器子类化并让你的子类忽略空行而不是对它们做某事,那么你可能会得到很好的服务;这样,来自其他应用程序的文件仍然看起来不错,您不必死在这些文件上。 :)
            • 是的。我也这么想。但是该文件具有以下内容:仅用于第一列(id)的行,以及下面行中的其余列。只是因为它看起来更好看。我需要将其设为单行并删除一个。我认为我会创建一个包含工作表和行索引列表的类,并在删除行时删除索引。太多了,但我需要删除行,我不明白为什么你不能用这个库删除行!
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多