I am trying to write out to an existing excel file. I don't want to create new rows or cells, I just want to write out the value from my array into the value at row x column y. Every time I have tried this so far I can only get it to work if I create a new row. Please help!!!
Integer columns = DataImport.columns_in_sheet[0];
Integer rowNum = learnerRow + 2;
try {
FileInputStream inp = new FileInputStream("D:/location/update.xlsx");
XSSFWorkbook wb = null;
wb = (XSSFWorkbook) WorkbookFactory.create(inp);
XSSFSheet sheet = wb.getSheetAt(0);
XSSFRow row = sheet.getRow(18);//places the start row
XSSFCell cell = null;//places the start column
cell = row.getCell(0);
//#########################################################################################
//#########################################################################################
for (int j = 0; j < exportData.length; j++) {
//sheet.createRow(rowNum+j);
//row = sheet.getRow(rowNum+j);
//row = sheet.getRow(rowNum+j);
for (int i=0; i < columns;i++){
cell.setCellType(CellType.STRING);
cell.setCellValue(exportData[j][i]);
}
}
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("D:/location/update.xlsx");
wb.write(fileOut);
fileOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
this code throws a null pointer because of row being null, I can only seem to get rid of the error by creating new rows. I am using XSSF formatting.
The logic of your code snippet is not clear. It looks not logically to me.
But to avoid NPE while using rows and cells from present sheets, one always needs check whether the row or cell was present already or needs to be new created. This is necessary because for not present rows Sheet.getRow will return null. Also Row.getCell will return null for not present cells.
So we can do:
Sheet sheet = ...
Row row = sheet.getRow(rowIdx); if (row == null) row = sheet.createRow(rowIdx);
Cell cell = row.getCell(cellIdx); if (cell == null) cell = row.createCell(cellIdx);
Now row either is a row which was already present or it is a new created row. And cell either is a cell which was already present or it is a new created cell. Neither row nor cell will be null. And at first present rows/cells will be got before they were new created if not present. So present rows and cells will not be destroyed.
The same is needed in loops:
Sheet sheet = ...
Row row;
Cell cell;
for (int rowIdx = 0; rowIdx < 10; rowIdx++) {
row = sheet.getRow(rowIdx); if (row == null) row = sheet.createRow(rowIdx);
for (int cellIdx = 0; cellIdx < 10; cellIdx++) {
cell = row.getCell(cellIdx); if (cell == null) cell = row.createCell(cellIdx);
// do something with cell
}
}
Related
I'm trying to modify the last cell of the rows in an excel workbook that in any cell match another value.
In the first iteration it works fine, but in the second loop I get this java.util.ConcurrentModificationException error in the for (Cell cell : row) { line.
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1486)
at java.base/java.util.TreeMap$ValueIterator.next(TreeMap.java:1531)
at Package.Fotos.initial(Fotos.java:266)
at Package.Fotos.main(Fotos.java:360)
Does anyone know what I'm doing wrong? This is the code I'm using based on this answer.
...
for (int i = 0; i < cuentafilas; i++) {
List<WebElement> columnas = filas.get(i).findElements(By.tagName("img"));
int cuentacolumnas = columnas.size();
for (int k = 0; k < cuentacolumnas; k++) {
String c = columnas.get(k).getAttribute("src");
if (c.contains("jpg")) {
String filtroValor = id;
Workbook libro = WorkbookFactory.create(new FileInputStream("D:\\archivos\\entrada.xlsx"));
DataFormatter formatter = new DataFormatter();
Sheet hoja = libro.getSheetAt(0);
for (Row row : hoja) {
for (Cell cell : row) {
CellReference cellRef = new CellReference(row.getRowNum(), cell.getColumnIndex());
String text = formatter.formatCellValue(cell);
if (filtroValor.equals(text)) {
Row fila = hoja.getRow(row.getRowNum());
int ultimaCelda = fila.getLastCellNum();
Cell celda = fila.createCell(ultimaCelda);
celda.setCellValue(c);
OutputStream os = new FileOutputStream("D:\\archivos\\entrada.xlsx");
libro.write(os);
}
}
}
}
}
}
...
Thanks.
The error lies in
Cell celda = fila.createCell(ultimaCelda);
where you create a new cell in the row.
You can't add a cell, while iterating over the list of all cells.
Try creating a copy of the list you are wanting to edit and iterate
over that one instead, so the other one becomes editable
the java.util.ConcurrentModificationException appears,
when editing a list, that you are currently iterating over.
I was trying to read data from an excel sheet that contains empty cells consider the following code:
File src = new File(path to your file);
FileInputStream fis = new FileInputStream(src);
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet1 = wb.getSheet("Sheet1");
int rowCount = sheet1.getLastRowNum();
System.out.println("total number of rows is: " + rowCount);
for(int i = 1; i < rowCount; i++) {
//getcell returns row num and starts from 1
//Also my sheet column contains data in numeric form
int data = (int) sheet1.getRow(i).getCell(1).getNumericCellValue();
System.out.println(data);
}
However, my code also reads the empty cells and displays the value as 0 (The cells have numeric value). How do I make my script read-only cells that are filled and display them while ignoring the ones that are empty?
Thank you in advance
Just update the for loop with an if condition which will check for the value which is getting retrieved from the Cell. PFB the updated for loop.
For Apache POI version 4.x you can try below-
for(int i = 1; i < rowCount; i++) {
//getcell returns row num and starts from 1
//Also my sheet column contains data in numeric form
Cell cell = sheet1.getRow(i).getCell(1);
int data = (int) sheet1.getRow(i).getCell(1).getNumericCellValue();
if(c.getCellType() == CellType.Blank)
{
continue;
}
else{
System.out.println(data);
}
}
For Apache POI version 3.x you can try below-
for(int i = 1; i < rowCount; i++) {
//getcell returns row num and starts from 1
//Also my sheet column contains data in numeric form
Cell cell = sheet1.getRow(i).getCell(1);
int data = (int) sheet1.getRow(i).getCell(1).getNumericCellValue();
if(cell.getCellType() == Cell.CELL_TYPE_BLANK)
{
continue;
}
else{
System.out.println(data);
}
}
I want to create an Excel file with Apache Poi, based on the sheet of another Excel file. Only the first two columns and their corresponding rows should be applied to the new Excel sheet.
First, I insert all cells of the first column, then I increment the columnIndex to insert the other cells.
private static void createNewWorkBook(XSSFSheet oldSheet) {
XSSFWorkbook newWorkbook = new XSSFWorkbook();
XSSFSheet newSheet = newWorkbook.createSheet("test-sheet");
for (int columnIndex = 0; columnIndex < 2; columnIndex++) {
int rowIndex = 0;
for (Row oldRow : oldSheet) {
XSSFRow newRow = newSheet.createRow(rowIndex);
XSSFCell newCell = newRow.createCell(columnIndex);
newCell.setCellValue("Hello"); // just for test purposes
// newCell.setCellValue(oldSheet.getRow(rowIndex).getCell(columnIndex).getStringCellValue());
rowIndex++;
}
}
try {
FileOutputStream fos = new FileOutputStream(new File("CreateExcelDemo.xlsx"));
newWorkbook.write(fos);
fos.close();
} catch (
IOException e) {
e.printStackTrace();
}
}
Unfortunatley it doesn't work. I only get the values of the second column in my newly generated excel-sheet. The first column is just empty.
BUT:
If I replace the columnIndex with 0 or 1, it works! Where is my thinking problem?
I am using apache poi to write the data in excel file. When I am passing value to columns of first row (for heading), its value does not get updated but from row 2 onward I can see the data in excel file.
Below is the code I am using.
public static void writeWorkBook(Map<String, List<String>> addressMap, List<String> userList) {
System.out.println("Writing Process Started ");
XSSFWorkbook workbook = new XSSFWorkbook();
for (String user : userList) {
XSSFSheet sheet = workbook.createSheet("Data_" + user);
int rownum = 1;
Row row = sheet.createRow(rownum);
Cell cell = row.createCell(0);
cell.setCellValue("User");
cell = row.createCell(1);
cell.setCellValue("Address");
List<String> addressList = addressMap.get(user);
for (String s : addressList) {
row = sheet.createRow(rownum++);
cell = row.createCell(0);
cell.setCellValue(user);
cell = row.createCell(1);
cell.setCellValue(s);
}
}
try {
FileOutputStream out = new FileOutputStream(new File("D://practice/java/testWrite.xlsx"));
workbook.write(out);
out.close();
System.out.println("testWrite.xlsx written successfully on disk.");
workbook.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The output I am getting is
First: All indexes are 0-based. So
...
int rownum = 1;
Row row = sheet.createRow(rownum);
...
creates the second row. First row would be
...
int rownum = 0;
Row row = sheet.createRow(rownum);
...
Second: In row = sheet.createRow(rownum++); at first the row is created and then rownum is incremented. So first row is created again instead of second row.
Do
...
row = sheet.createRow(++rownum);
...
instead.
Getting and setting the rows are 0-based, so if you want to have the description in the first row, you need use 0 as argument in
Row row = sheet.createRow(rownum);
I have the arraylist of data in the following format :
ArrayList> listResultData. Now collection contains around 11k+ rows to be inserted in the excel.
When i insert these 11490 rows in excel it took 6 hrs to insert the records, that means its very bad performance issue. Is there anyway to insert the data in excel in chunks for 1000 rows at a time (means there should be something like executeBatch() in sql for inserting records). A row contains 4-5 columns also.
Following is the code i have been using :
public boolean setArrayListData(String sheetName, ArrayList<ArrayList<String>> listResultData) {
try {
fis = new FileInputStream(path);
workbook = new XSSFWorkbook(fis);
int index = workbook.getSheetIndex(sheetName);
if (index == -1)
return false;
sheet = workbook.getSheetAt(index);
int colNum = 0;
int rowNum = this.getRowCount(sheetName);
rowNum++;
for (ArrayList<String> al : listResultData) {
for (String s : al) {
sheet.autoSizeColumn(colNum);
row = sheet.getRow(rowNum - 1);
if (row == null)
row = sheet.createRow(rowNum - 1);
cell = row.getCell(colNum);
if (cell == null)
cell = row.createCell(colNum);
// cell style
// CellStyle cs = workbook.createCellStyle();
// cs.setWrapText(true);
// cell.setCellStyle(cs);
cell.setCellValue(s);
//System.out.print("Cell Value :: "+s);
colNum++;
}
rowNum++;
colNum = 0;
//System.out.println("");
}
fileOut = new FileOutputStream(path);
workbook.write(fileOut);
fileOut.close();
workbook.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Please suggest !!
Instead of XSSF you may want to try SXSSF the streaming extension of XSSF. In contrast to xssf where you have access to all rows in the document which can lead to performance or heap space issue sxssf allows you to define a sliding window and limits the access to rows in that window. You can specify the window size at construction time of your workbook using new SXSSFWorkbook(int windowSize) . As you then create your rows and the number of rows exceed the specified window size, the row with the lowest index is flushed and is no longer in memory.
Find further infos at SXSSF (Streaming Usermodel API)
Example:
// keep 100 rows in memory, exceeding rows will be flushed to disk
SXSSFWorkbook wb = new SXSSFWorkbook(100);
Sheet sh = wb.createSheet();
for(int rownum = 0; rownum < 1000; rownum++){
//When the row count reaches 101, the row with rownum=0 is flushed to disk and removed from memory,
//when rownum reaches 102 then the row with rownum=1 is flushed, etc.
Row row = sh.createRow(rownum);
for(int cellnum = 0; cellnum < 10; cellnum++){
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
}