I'm using Apache POI to save data to an excel file. Basic data is being saved fine, but I need to also use formula's.
Its adding the formula in, but its not being evaluated until I refresh the cell (clicking into and pressing enter)
The code I'm using to create the cells. Removed code that's not relevant
public void writeExcel(ClassManager cm) throws FileNotFoundException, IOException {
setupRows();
workbook.setForceFormulaRecalculation(true);
FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
workbook.close();
}
public void setupRows() {
setupRow15();
}
public void setupRow15() {
int start = 2;
Row row = sheet.createRow(16);
// Create 1st Cell
Cell cell = row.createCell(0);
cell.setCellValue("templateId = ");
for (int i = 0; i < classes.size(); i++) {
// Get class
Classes c = classes.get(i);
// Create cell
cell = row.createCell(start);
// Set contents
cell.setCellFormula("IF(C3=\"\",\"\",CONCAT($A17,$B17,C" + (start + 1) + ",$B17,$A$16))");
start++;
}
}
It's resulting in the formula
Solved it by running after setting all formulas
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
for (Row r : sheet) {
for (Cell c : r) {
evaluator.evaluateFormulaCell(c);
}
}
Related
I am trying to update a column in the excel sheet but only the first row is getting update. The second iteration is not working. Could anyone help me on this? Below is my code that I am trying.
String excelPath = "path";
String YES = "Updated YES";
String NO = "Updated NO";
try {
FileInputStream fis= new FileInputStream(excelPath);
HSSFWorkbook workSheet = new HSSFWorkbook(fis);
Cell cell = null;
FileOutputStream output_file =new FileOutputStream(excelPath);
for (int i = 0; i < TCID.size(); i++) {
HSSFSheet sheet1 = workSheet.getSheetAt(0);
String data = sheet1.getRow(i+1).getCell(i).toString();
if(data.equals(TCID.get(i))){
cell = sheet1.getRow(i+1).getCell(i+2);
cell.setCellValue(YES);
workSheet.write(output_file);
}else {
cell.setCellValue(NO);
workSheet.write(output_file);
}
}
fis.close();
output_file.close();
workSheet.close();
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My latest code is below. Now it is updating the columns but the last row is not getting updated. What am i missing.
FileInputStream fis= new FileInputStream(excelPath);
HSSFWorkbook workSheet = new HSSFWorkbook(fis);
HSSFSheet sheet1 = workSheet.getSheetAt(0);
//FileOutputStream output_file =new FileOutputStream(excelPath);
for (int i = 0; i < TCID.size(); i++) {
String data = sheet1.getRow(i+1).getCell(0).toString();
Cell cell = sheet1.getRow(i+1).getCell(2);
if(data.equals(TCID.get(i))){
cell.setCellValue(YES);
}else {
cell.setCellValue(NO);
}
}
fis.close();
//output_file.close();
//workSheet.close();
FileOutputStream output_file =new FileOutputStream(excelPath);
workSheet.write(output_file);
output_file.close();
The row and the column are both keyed off 'i', so you'll be traversing the sheet diagonally.
But certainly do the things the other people are recommending too, they are all good suggestions.
Typically when working with a two dimensional block of information, I find it useful to have one loop for rows and then nested inside that a loop for columns (or vice versa)
e.g.
for (y = startRow; y <= maxRow; y++) {
....
for (x = startCol; x <= maxCol; x++) {
.... // do something to each column in the current row
cell = sheet1.getRow(y).getCell(x);
.....
Ok, so there are a couple of things.
Declare HSSFSheet sheet1 = workSheet.getSheetAt(0); outside of your loop. You are working with the same sheet each iteration of your for loop, so this only has to be invoked once.
Your logic to get the cell data (String data = sheet1.getRow(i+1).getCell(i).toString();) will not return you the same column. On your first iteration, you'll get (R)ow 1 : (C)olumn 0. The next iteration will return R2 : C1, then R2:C2, then R3:C3, etc. Notice the pattern that you are going diagonally down the columns, not vertically.
Rows start at 0.
You only need to workSheet.write(output_file); once you have done all your processing.
If the Row does not exist you will get a NullPointerException
As you are working with a unique Cell each iteration, you just declare it in the loop (so no need for Cell cell = null; outside your loop).
Here is a an example:
try {
FileInputStream fis = new FileInputStream(excelPath);
Workbook workbook = new HSSFWorkbook(fis);
Sheet sheet = workbook.getSheetAt(0);
for (int i = 0; i < 5; i++) {
Row row = sheet.getRow(i);
if (row != null) {
Cell cell = row.getCell(0);
cell.setCellValue("Updated cell.");
}
}
FileOutputStream output_file = new FileOutputStream(excelPath);
workbook.write(output_file);
output_file.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
I think moving Cell reference inside for loop should fix it for you.
Cell cell = null;
Also you might also need to move outside if-block incase you face NullPointerException in else-block
cell = sheet1.getRow(i+1).getCell(i+2)
Something like this...
HSSFSheet sheet1 = workSheet.getSheetAt(0);
for (int i = 0; i < TCID.size(); i++) {
String data = sheet1.getRow(i+1).getCell(0).toString();
Cell cell = sheet1.getRow(i+1).getCell(2);
if(data.equals(TCID.get(i))){
cell.setCellValue(YES);
}else {
cell.setCellValue(NO);
}
workSheet.write(output_file)
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
EDIT: I am using this code to read rows and columns of an excel sheet.But the line marked with double star throws exception(java.lang.nullpointer exception).Apart from this i also want to convert null columns found in between to blank columns.Please help.
There are 2 loops one for row and inner one for column as obvious. Niehter the row is getting read nor the blank cell issue is getting resolved.
public void read(String filePath) throws NullPointerException {
try {
FileInputStream file = new FileInputStream(new File(filePath));
System.out.println("going to create Workbook object to read excel row wise");// Create Workbook instance holding reference to .xlsx file
XSSFWorkbook workbook = new XSSFWorkbook(file);
System.out.println("going to create object sheet to read excel row wise");
XSSFSheet sheet = workbook.getSheetAt(0); //extracts the first sheet of excel
System.out.println("Running row iterator to read excel row wise");
for (int rowNumber = sheet.getFirstRowNum(); rowNumber <= sheet.getLastRowNum(); rowNumber++) {
if (rowNumber == sheet.getFirstRowNum())// this row was skipped as it was header row.
{
System.out.println("skipping first row");
continue;
}
this.rowconcat = ""; // all values of perticular row will be concatinated in this variable.
this.flag = 0;
if (sheet.getRow(rowNumber) == null) {
System.out.println("row detected null");
} else {
// The row has data
System.out.println("row no inside else==="+rowNumber);
**Row row = sheet.getRow(rowNumber);** //This line here throws null pointer exception.
for (int cellNumber = row.getFirstCellNum(); cellNumber <= row.getLastCellNum(); cellNumber++) {
Cell cell = row.getCell(cellNumber);
if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
this.flag = 1; // set to 1 to indicate blank cell but this also doesn't work
cell.setCellType(Cell.CELL_TYPE_STRING);
cell.setCellValue(" "); //inserting space in cell after converting its type to String.
this.rowconcat = this.rowconcat + cell.getStringCellValue() + "~";
} else {
cell.setCellType(Cell.CELL_TYPE_STRING);
this.rowconcat = this.rowconcat + cell.getStringCellValue() + "~";
}
}
}
}
}//try block closure
catch(Exception e){
//autogenerated
}
} // function closure
I recommend JXL library better the appache one, I have worked with it sinc elong time. Its only minor problem is that it works only with xls not xlsx (if no updates have taken place till now!).
Have a small example for that:
File xlsFile;
public void manageData ()
{
Workbook w;
try {
w = Workbook.getWorkbook(xlsFile);
// Get the first sheet
Sheet sheet = w.getSheet(0);
int j = 1;
//Begin from the second row
while (j < sheet.getColumns()) {
//staff
Cell infoCell = sheet.getCell(j, 4);
System.out.println(infoCell.getContents());
}
catch (Exception e)
{
}
}
I want to remove the cell content but keeping its style but it's always remove the style and content. Here's my code:
private static void RefreshReport(String sheetName, String resultColumn) {
try {
InputStream inp = new FileInputStream(getExcelFile());
Workbook wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheet(sheetName);
int colResult = getColumnResult(sheet, resultColumn);
int rowStart = getRowResult(sheet, resultColumn);
int rowEnd = Math.max(20, sheet.getLastRowNum());
for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
Row r = sheet.getRow(rowNum);
if (r != null) {
Cell cell = r.createCell(colResult);
if (cell.getCellType() != Cell.CELL_TYPE_BLANK) {
CellStyle cs = wb.createCellStyle();
cs = cell.getCellStyle();
r.removeCell(cell);
cell = r.createCell(colResult);
cell.setCellStyle(cs);
}
}
}
FileOutputStream fileOut = new FileOutputStream(getExcelFile());
wb.write(fileOut);
fileOut.close();
inp.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Any help would be great.
The reason that your method isn't working is that you are always calling createCell if the the row r is not null. This will overwrite any Cell that already exists, including contents and styling.
What you need to do is call getCell instead. This will retrieve the Cell at that column index, provided it exists, or null if it doesn't exist. Then if it exists, you can process the Cell as you are doing.
if (r != null) {
Cell cell = r.getCell(colResult);
if (cell != null && cell.getCellType() != CellType.BLANK) {
// rest of your code here
In an alternative to the delete/re-create method you have, you can just set the cell type to BLANK. This will set the contents to blank, but it will also preserve the cell style currently on that cell. There is no need to delete the cell and re-create it.
if (cell.getCellType() != CellType.BLANK) {
cell.setCellType(CellType.BLANK);
}
Related to the rgettman's comment.
But in POI 5.0, you should use cell.setBlank() instead, because cell.setCellType(CellType.BLANK) is deprecated.
private String[][] data;
// to read from excel file
public void readFile() throws IOException {
// Path to the excel file
// File datafile = new File("C:\\Users\\atomar\\Documents\test.xlsx");
// A Buffered File Input Stream to read the data
FileInputStream f = new FileInputStream(
"C:\\Users\\atomar\\Documents\\test.xlsx");
System.out.println("file found");
// InputStream fis = new BufferedInputStream(new FileInputStream("f"));
// We create a workbook which represents the excel file
XSSFWorkbook book = new XSSFWorkbook(f);
// Next a sheet which represents the sheet within that excel file
XSSFSheet sheet = book.getSheet("Sheet1");
// No of rows in the sheet
int rowNum = sheet.getLastRowNum() + 1;
System.out.println("rowNum");
// No of columns in the sheet
int colNum = sheet.getRow(0).getLastCellNum();
// A Two dimensional array of Strings which represents the data in the
// sheet
data = new String[rowNum][colNum];
{
for (int i = 0; i < rowNum; i++) {
// Get the row
XSSFRow row = sheet.getRow(i);
for (int j = 0; j < colNum; j++) {
// Get the columns or cells for the first row and keep
// looping
// for the other rows
XSSFCell cell = row.getCell(j);
// Make a call to the method cellToString which actually
// converts the cell contents to String
data[i][j] = cellToString(cell);
// data[i][j] = value;
// Here is where you write the logic to handle the data.I am
// just printing out the contents here.
//System.out.println("The value is " + data[i][j]);
}
}
Here I am calling that function
public void InterestedParty() throws InterruptedException {
try {
readFile();
} catch (IOException e1) {
}
}
Getting error: There are no support for this type of cell
I deleted two row data from input excel file then it started before it was working fine. But now I have deleted those row completely the also issue is there
if there is no data, XSSFCell will be null. Check whether it is null or not. After call your cellToString() method.
XSSFCell cell = row.getCell(j);
if(cell != null) {
data[i][j] = cellToString(cell);
} else {
// if you would like to set value when cell is null
row.createCell(j).setCellValue(your value);
}
You can have a row with data, an empty row next then another row with data. The middle row can be viewed as null if is undefined, so my advice is to use an iterator for the rows.
RowIteratior here is a good start.
Also, once you have the row, you can use cell iterator to iterate over the cells. Keep in mind that an undefined cell will be viewed as null and skipped, but an empty cell is not null!
Cell iterator is doc'ed here.
Your approach is also good, but you need to check for nulls or empty at each iteration before working with the objects.
[better quality]:. http://imageshack.us/photo/my-images/51/v5cg.png/
Problem: i use formulas in my workBook.xlsx. Depending on the circumstances i change value (3,3). At this example i changed 10 to 20. And after that i want to calculate the formula, which use this cell. When it has finished, it will override the value of the cells, remove formula and record the value. This cell no longer be used for the calculations again.
Code:
public class ReaderXlsx {
public List<List<String>> ReaderXlsx(String sfilename, int firstColumn, int columnsCount, int rowsCount, int moduleCount){
int lastColumn=firstColumn+columnsCount;
List<List<String>> rowsContent = new ArrayList<List<String>>();
try ( FileInputStream fileInputStream = new FileInputStream("C:\\Users\\student3\\"+sfilename+".xlsx");)
{
XSSFWorkbook workBook = new XSSFWorkbook(fileInputStream);
XSSFSheet sheet = workBook.getSheetAt(0);
int firstRow = findOneInFirstColumn(sheet,50);
setModuleCount(sheet,moduleCount);
workBook.getCreationHelper().createFormulaEvaluator().evaluateAll();
toNewLine:
for (int lineId=firstRow;lineId<rowsCount;lineId++) {
List<String> columnsContent = new ArrayList<String>();
Row row = sheet.getRow(lineId);
if (row==null){continue toNewLine;}
if (row.getCell(2)==null || row.getCell(2).getStringCellValue().equals("") ) {continue toNewLine;}
for (int columnId=firstColumn+1;columnId<lastColumn;columnId++) {
Cell cell = row.getCell(columnId-1);
if ((cell==null)) { continue toNewLine;}
cell.setCellType(Cell.CELL_TYPE_STRING);
if ((columnId==0 & cell.getStringCellValue().equals(""))) {continue toNewLine;}
if ((columnId==5 & cell.getStringCellValue().equals("")) || (columnId==6 & cell.getStringCellValue().equals(""))) cell.setCellValue("0");
columnsContent.add(cell.getStringCellValue());
}
rowsContent.add(columnsContent);
}
try(FileOutputStream out = new FileOutputStream("C:\\Users\\student3\\Used"+sfilename+".xlsx"); ) {
workBook.write(out);
out.close(); }
}
catch (IOException e) {
e.printStackTrace();
}
return rowsContent;
}
private Integer findOneInFirstColumn(XSSFSheet sheet, Integer maxRows){
int result=0;
toNextLine:
for (int lineId=0;lineId<maxRows;lineId++){
Row row = sheet.getRow(lineId);
if (row==null | row.getCell(0)==null) {result++; continue toNextLine; }
else{
row.getCell(0).setCellType(Cell.CELL_TYPE_STRING);
if (row.getCell(0).getStringCellValue().equals("1")){return result;}
else {result++;}
}
}
return result;
}
private void setModuleCount(XSSFSheet sheet, Integer moduleCount){
Row row = sheet.getRow(1);
if (moduleCount==0) {}
if (moduleCount>0) {row.createCell(2).setCellValue(moduleCount.toString());}
}
}
Now i use 2 files, because i need to save my formulas. I want to use only 1 (source) and update it correctly.