1

I want to fill table a template excel file. I want to insert rows and fill them. I used java Apache POI library to access excel files. At first, I created a new file and filled column A from row 1 to 10 with 1..10 numbers and saved the file. Then I read the file and tried to insert a single empty row with a sheet.shiftRows() method. I tried below code but output file has a problem in the opening (reading) and rows 5,6,7 are empty and move has not occurred.

InputStream inputStream = new FileInputStream("TestIn-1.xlsx");
Workbook workbookIn = new XSSFWorkbook(inputStream);
Sheet sheetIn = workbookIn.getSheet("Sheet1");

sheetIn.shiftRows(4,5,1);

OutputStream outputStream = new FileOutputStream("TestOut.xlsx");
workbookIn.write(outputStream);
outputStream.close();
Uwe Allner
  • 3,399
  • 9
  • 35
  • 49
Moh Tarvirdi
  • 685
  • 1
  • 13
  • 25

1 Answers1

11

Your shiftRows tries shifting rows between row 5 (index 4) and row 6 (index 5) one row down. But what about row 7, 8, 9 and 10? You needs shifting rows between row 5 and last row one row down if the need is getting a new empty row 5.

Using apache poi version 3.17 this is as simple as:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;

class ExcelReadShiftRowsAndWrite {

 public static void main(String[] args) throws Exception {
  //String fileIn= "TestIn.xls";
  //String fileOut= "TestOut.xls";
  String fileIn= "TestIn.xlsx";
  String fileOut= "TestOut.xlsx";

  try (Workbook workbook = WorkbookFactory.create(new FileInputStream(fileIn));
       FileOutputStream out = new FileOutputStream(fileOut)) {

   Sheet sheet = workbook.getSheet("Sheet1");

   sheet.shiftRows(4, sheet.getLastRowNum(), 1); //shifts rows between row 5 (index 4) and last row one row down

   workbook.write(out);
  } 
 }
}

But apache poi versions greater than 3.17, also 4.1.0, have a bug in shiftRows using XSSF. There, after shifting, the references in the cells remain old instead being adjusted to the new rows. For example the references A5, A6, ... remain after shifting down instead of getting adjusted to A6, A7, ...

So this bug must be corrected:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;

class ExcelReadShiftRowsAndWrite {

 public static void main(String[] args) throws Exception {
  //String fileIn= "TestIn.xls";
  //String fileOut= "TestOut.xls";
  String fileIn= "TestIn.xlsx";
  String fileOut= "TestOut.xlsx";

  try (Workbook workbook = WorkbookFactory.create(new FileInputStream(fileIn));
       FileOutputStream out = new FileOutputStream(fileOut)) {

   Sheet sheet = workbook.getSheet("Sheet1");

   sheet.shiftRows(4, sheet.getLastRowNum(), 1); //shifts rows between row 5 (index 4) and last row one row down

   if (sheet instanceof XSSFSheet) {  
    XSSFSheet xSSFSheet = (XSSFSheet)sheet;
    // correcting bug that shiftRows does not adjusting references of the cells
    // if row 3 is shifted down, then reference in the cells remain r="A3", r="B3", ...
    // they must be adjusted to the new row thoug: r="A4", r="B4", ...
    // apache poi 3.17 has done this properly but had have other bugs in shiftRows.
    for (int r = xSSFSheet.getFirstRowNum(); r < sheet.getLastRowNum() + 1; r++) {
     XSSFRow row = xSSFSheet.getRow(r); 
     if (row != null) {
      long rRef = row.getCTRow().getR();
      for (Cell cell : row) {
       String cRef = ((XSSFCell)cell).getCTCell().getR();
       ((XSSFCell)cell).getCTCell().setR(cRef.replaceAll("[0-9]", "") + rRef);
      }
     }
    }
    // end correcting bug
   }

   workbook.write(out);
  } 
 }
}
Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • Thanks, correction loop solved the problem. can we write in general format not dependent on XSSF type? Another problem is when changing the value of the inserted blank row is modified, calculation not done. (Add sum to end of rows and fill blank value with 100) – Moh Tarvirdi May 04 '19 at 08:51
  • @Moh Tarvirdi: "Can we write in general format not dependent on XSSF type?": My code is independent of type except the bug correction which needs to be `XSSF`only. "When this bug will be solved (estimation)?": I don't know. I am not part of the `apache poi` developer team. I am only a user of `apache poi`. "...calculation not done.": That's another question. See [Recalculation of Formulas](https://poi.apache.org/components/spreadsheet/eval.html#recalculation). Simplest solution: Do `workbook.setForceFormulaRecalculation(true);` before `workbook.write(out);`. – Axel Richter May 04 '19 at 09:08
  • Great, Many Thanks. How can I create new row same as (border, style,..) of the specified row? I want to have a table template and fill rows, so need to keep style. I can clone a row and fill it as a row, insert row with data and keep last row summations. – Moh Tarvirdi May 04 '19 at 09:17
  • 1
    @Moh Tarvirdi: Asking a concrete question and getting a concrete answer, this is how Stackoverflow works. Asking follow up questions one after the other in comments is not how Stackoverflow works. Please ask a new question about this other problem and provide all necessary informations in that new question. Stackoverflow Questions/Answers shall be helpful for other readers too, not only for you. Stackoverflow is not a support forum. – Axel Richter May 04 '19 at 09:29
  • Dear Axel, Yes you are right. I will do your recommendation. Thanks again for advice. – Moh Tarvirdi May 04 '19 at 09:51
  • This really helps! Thanks. – Nguyen Tuan Anh May 11 '21 at 15:13