How to delete contents of an Excel sheet in Java? - java

How to delete contents of an Excel sheet in an Excel workbook, using Java SE and Apache POI?

As mentioned in previous comments
Sheet sheet = wb.getSheetAt(0);
for (Row row : sheet) {
sheet.removeRow(row);
}
this code throwing ConcurrentModificationException to me. So, I have modified the code and it's working fine. Here is the code:
Sheet sheet = wb.getSheetAt(0);
Iterator<Row> rowIte = sheet.iterator();
while(rowIte.hasNext()){
rowIte.next();
rowIte.remove();
}

I've found that removeSheetAt/createSheet isn't really an acceptable answer, because you can't put the new sheet into the correct position in the workbook without running into a bug in WorkSheet.setSheetOrder
This code snippet
Sheet sheet = wb.getSheetAt(0);
for (Row row : sheet) {
sheet.removeRow(row);
}
in my world throws a ConcurrentModificationException
I had to resort to
for (int index = crnt.getLastRowNum(); index >= crnt.getFirstRowNum(); index--) {
crnt.removeRow( crnt.getRow(index));
}

Depending on what contents you want to delete you may remove a single cell or row.
Too erase the complete sheet iterate over all rows and delete it.
Sheet sheet = wb.getSheetAt(0);
for (Row row : sheet) {
sheet.removeRow(row);
}

I know this is an old thread but I think I found the best solution
What I did was just create a new workbook of the same type and save it over the file that I wanted to delete.
Heres the code
private void clearOldFile(){
FileOutputStream out = null;
try{
oldFile = new XSSFWorkbook();
Sheet sheet = oldFile.createSheet("temp data");
out = new FileOutputStream(AbsolutePathForTempExcelFile);
oldFile.write(out);
out.close();
} catch(Exception e){
e.printStackTrace();
}
}

You probably want to use HSSFWorkbook.removeSheetAt(index).

I guess it is an old thread but I also get ConcurrentModificationException. Based on VoiceOfUnreason I found this to work:
while (xlsSheet.getPhysicalNumberOfRows() > 0) {
xlsSheet.removeRow(xlsSheet.getRow(xlsSheet.getLastRowNum()));
}
if (xlsSheet.getDrawingPatriarch() != null) {
xlsSheet.getDrawingPatriarch().clear();
}

I also got concurrent modification exception, also using the more "modern" way of doing it :
sheet.forEach(r->sheet.remove(r));
The iterator based solution from #Thirupathi S apparently worked, but for reasons I don't exactly know it was creating xslx files that were not readable by Apple's Numbers and OSX preview (and probably other softwares too).
I suspect this has something to do with the iterator not removing something: the code of the removeRow method is way more complex than the simple iterator remove operation.
Using old plain for-loop with reversed index worked like a charm :
for (int i = sheet.getLastRowNum(); i >= 0; i--) {
sheet.removeRow(sheet.getRow(i));
}

This solution works fine with me. And also consider special cases, e.g. the sheet is blank, or the spaces between the firstRow and lastRow are present.
public void cleanSheet(Sheet sheet) {
int numberOfRows = sheet.getPhysicalNumberOfRows();
if(numberOfRows > 0) {
for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
if(sheet.getRow(i) != null) {
sheet.removeRow( sheet.getRow(i));
} else {
System.out.println("Info: clean sheet='" + sheet.getSheetName() + "' ... skip line: " + i);
}
}
} else {
System.out.println("Info: clean sheet='" + sheet.getSheetName() + "' ... is empty");
}
}

My reason for not deleting and recreating sheet: Keep references to sheet-scoped names working.
for(int i = sheet.getLastRowNum(); i >= 0; i--)
{
Row row = sheet.getRow(i);
if(row != null)
{
sheet.removeRow(row);
}
}

The other iterator methods appeared to work but Excel then refused to open the file.
This one worked for me:
int rownum;
while ((rownum=sheet.getLastRowNum()) > 0) sheet.removeRow(sheet.getRow(rownum));

Related

Java Out of memory error for reading from and writing to an xlsx

I need to read several xlsx files looking for data specific to an employee and simultaneously create another xlsx file (if I find data in any of the file)with file name as employee Id appended to the name I found the data in. Eg. there is an employee with emp id 1 and there are severaal xlsx files such as A,B, C... so on; I need to look for data relating to emp id 1 in each file and for the files I get a hit I need to create a file named 1_A.xlsx.
Now although I have built the logic and am using Apache POI APIs for reading and writing, my code is throwing Out Of Memory error after creating just the first file with the data. And is unable to read the rest of the files.
I have tried using SXSSF instead of XSSF but same OOM happens.
Increasing the heap space is not an option for me.
Please help here...Thanks in advance.
Here is a piece of code :
//Reader:
Row row = null;
List<Row> listOfRecords = new ArrayList<Row>();
try {
FileInputStream fis = new FileInputStream(metaDataFile);
new InputStreamReader(fis, "ISO-8859-1");
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheetAt(0);
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
row = rowIterator.next();
if (!isEmptyRow(row)) {
listOfRecords.add(row);
}
}
wb.close();
fis.close();
//Writer
LOGGER.info("in createWorkbook " );
Workbook empWorkbook = new SXSSFWorkbook(200);
Sheet empSheet = empWorkbook.createSheet("Itype Sheet For Emp_"
+ personnelNumber);
int rowNum = listOfRecords.size();
System.out.println("Creating excel");
Cell c = null;
for (int i = 0; i < rowNum; i++) {
Row record = listOfRecords.get(i);
Row empRow = empSheet.createRow(i++);
if (!isEmptyRow(record)) {
int colNum = record.getLastCellNum() + 1;
for (int j = 0; j < colNum; j++) {
Cell newCell = empRow.createCell(j);
System.out.println("cellVal:"
+ String.valueOf(record.getCell(j)));
newCell.setCellValue(String.valueOf(record.getCell(j)));
}
}
}
The writer method is called from within the reader.
Reading of multiple xlsx files is indeed tricky business butI finally solved it.
I had to break down my code several folds to realise that the OOM error was due to the fact that after reading 3 files no more memory was left to process the rest of the files.
xlsx files are compressed xml files. So when we try to read them using XSSF or SXSSF APIs it loads the entire DOM to the memory thereafter choking it.
I found an excellent solution here :
[https://github.com/monitorjbl/excel-streaming-reader]
Hope this will help others who come here facing the same issue.

What is causing excel to crash after updating file thru java?

I have some java code that opens an excel sheet, adds auto filter to a group of columns, then saves and closes. The problem is that when a user opens the file and trys to sort smallest to largest or largest to smallest excel will freeze then crash. But if you first filter then you can sort with out issue and it does not freeze and crash.
private static void AddFilter()
{
//Adds filter to the rows in Column 2
try
{
FileInputStream fileIn = new FileInputStream("C:\\Users\\gria\\Desktop\\Fleet Manager Summary.xls");
HSSFWorkbook report = new HSSFWorkbook(fileIn);
Sheet sheet = report.getSheetAt(0);
sheet.setAutoFilter(CellRangeAddress.valueOf("A5:P5"));
FileOutputStream fileOut = new FileOutputStream("C:\\Users\\gria\\Desktop\\Fleet Manager SummaryT.xls");
report.write(fileOut);
fileOut.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Thank you,
UPDATE:
After some experimenting I have updated the info and code since the original question was asked to better explain the problem.
Try changing
XSSFFormulaEvaluator.evaluateAllFormulaCells(report);
to
HSSFFormulaEvaluator.evaluateAllFormulaCells(report);
XSSFFormulaEvaluator.evaluateAllFormulaCells() works for XSSfWorkbook, but not for the HSSFWorkbook.
Documentation
Also,
you can edit your commented code to:
for(int i = 5; i < sheet.getLastRowNum(); i++)
{
Cell cell = sheet.getRow(i).getCell(6);
//I don't know if you have data in all of the cells,
//So I suggest you to evaluate null
if(cell != null && !cell.getStringCellValue().isEmpty())
{
cell.setCellValue(Double.valueOf(cell.getStringCellValue()).doubleValue());
}
}

read an external worksheet using apache poi in java

I am trying to create an excel which has the names. I need to execute a formula which needs to reference an external worksheet.
String formula = "=VLOOKUP(A2,[asd.xlsx]Sheet1!B$2:L$2045,11,0)";
System.out.println("formula: "+formula);
cell1.setCellFormula(formula);
When I execute this, I get the following exception.
java.lang.RuntimeException: not implemented yet
at org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook.getExternalSheetIndex(XSSFEvaluationWorkbook.java:127)
at org.apache.poi.ss.formula.FormulaParser.createAreaRefParseNode(FormulaParser.java:615)
I tried to use INDIRECT function, set that formula as text and execute the INDIRECT, but it did not work. Am I missing something?
Thanks.
Update 1:
Thanks for the comments. I did not use XSSFEEvaluationWorkbook. My code is below
FileInputStream abc = new FileInputStream(new File("Z_abc.xlsx"));
XSSFWorkbook workbookabc = new XSSFWorkbook(abc);
XSSFSheet sheetabc = workbookabc.getSheetAt(0);
Iterator<Row> rowIteratorRead = sheetabc.iterator();
while (rowIteratorRead.hasNext())
{
Row rowRead = rowIteratorRead.next();
if(rowRead.getRowNum()==0){
continue;
}//if(row.getRowNum()==0){
Cell cell = rowRead.getCell(0);
Cell cell1 = rowRead.getCell(1); //////////////////////////
if(cell1 == null) {
cell1 =rowRead.createCell(1);
int rowNumber = (rowRead.getRowNum()+1);
String formula = "VLOOKUP(A2,[asd.xlsx]Sheet1!B$2:L$2045,11,0)";
//System.out.println("formula: "+formula);
cell1.setCellFormula(formula);
//cell1.setCellValue(formula);
}//if(cell1 == null) {
}//while (rowIteratorRead.hasNext())
I was successful in getting the formulas work if they refer from same workbook without using XSSFEEvaluationWorkbook.
Thanks.

Excel cannot understand the format of data written by java

I am having 2 issues using the apache POI to write data from a csv into an excel file.
The data consists of dates, and numbers
The issues are:
1) The numbers are written as strings.
2) Excel cannot read the date format (this messes the graphs up)
The code (that I received help with previously):
String name = "test";
Sheet sheet = wb.getSheet(name);
if (sheet == null) {
sheet = wb.createSheet(name);
}
int rowCount = 0;
Scanner scanner = new Scanner(new File("/tmp/" + name + ".csv"));
while (scanner.hasNextLine()) {
String[] rowData = scanner.nextLine().split(",");
for (int col = 0; col < rowData.length; col++) {
Row row = sheet.getRow(rowCount);
if (row == null)
row = sheet.createRow(rowCount);
Cell cell = row.getCell(col);
if (cell == null) {
cell = row.createCell(col);
}
cell.setCellValue(rowData[col]);
}
rowCount++;
}
wb.write(new FileOutputStream(excel));
}
1) I tried using Double.parseDouble(rowData[col]) when entering the data into the excel file. but this gives an empty string error. I even set the cell format with style.setDataFormat(format.getFormat("#,##0.0000")); but it still does not work
2) I tried using the date format cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yyyy hh:mm:ss")); but still the excel graphs can't read this format. (when I manually copy and paste from the csv file it works).
So basically, when copying data using the apache poi, none of the other data that relies on the copied cells is updated.
for example if a cell has a value of the average of 100 cells, and I manually copy data into those cells, it updates automatically. But when it copies through java, the cells do not update.
The following should do something more.
try {
double value = Double.parseDouble(rowData[col]);
cell.setCellValue(value);
} catch (NumberFormatException | NullPointerException e) {
String value = rowData[col];
cell.setCellValue(value);
}
(However you might not use Apache POI and straight copy the CSV file to a .xls, if
it is just a need for double-click reading by Excel.)

How to update cell reference values using Apache POI

I am using Apache POI to create new XSSFWorkbook from an existing one, after updating some values. Suppose I have two worksheets (Lets say: worksheet A & B) in my existing workbook. Worksheet B has some cell reference from Worksheet A. IF i modify those cell values of worksheet A and save them as a new workbook, corresponding cell values of worksheet B should be updated too. But it doesn't. How can i update them programmatically? . Thank you.
My code:
public void createExcel(ClientData cd) throws FileNotFoundException, IOException, InvalidFormatException{
// create a new file
double[] dataHolder1= cd.getFinalData1(), param1 = cd.getRecord1Param();
double[] dataHolder2 = cd.getFinalData2(), param2 = cd.getRecord2Param();
double[] ncv = cd.getNcv();
String[] pname = cd.getName();
Workbook workbook = new XSSFWorkbook(OPCPackage.open(new FileInputStream("template/mncv.xlsx"))); // or sample.xls
//CreationHelper createHelper = workbook.getCreationHelper();
Sheet s=workbook.getSheetAt(0);
int counter = dataHolder1.length + param1.length +param2.length+dataHolder2.length;//+ param1.length + param2.length;
// r = s.getRow(0);
// r.getCell(0).setCellValue("Param1");
// r.getCell(1).setCellValue("Record1");
// r.getCell(2).setCellValue("Param2");
// r.getCell(3).setCellValue("Record2");
int i;
for(i=0;i<counter;i++){
if(i<param1.length){
for(int j=0;j<param1.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(param1[j]);
i++;
}
}else if(i<dataHolder1.length+param1.length && i>=param1.length){
for(int j=0;j<dataHolder1.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(dataHolder1[j]);
i++;
}
}else if(i<dataHolder1.length+param1.length+param2.length && i>=dataHolder1.length+param1.length){
for(int j=0;j<param2.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(param2[j]);
i++;
}
}else{
for(int j=0;j<dataHolder2.length;j++){
r = s.getRow(i);
r.getCell(0).setCellValue(dataHolder2[j]);
i++;
}
}
// if(i<=param1.length){
// r.getCell(0).setCellValue(param1[i-1]);
// r.getCell(2).setCellValue(param2[i-1]);
//
// }
// r.getCell(0).setCellValue(param1[i]);
//r.getCell(3).setCellValue(dataHolder2[i-1]);
i--;
}
for(int k=0;k<ncv.length;k++){
r = s.getRow(i);
r.getCell(0).setCellValue(ncv[k]);
i++;
}
s = workbook.getSheetAt(1);
s.getRow(2).getCell(5).setCellValue(pname[0]+" "+pname[1]+" "+pname[2]);
s.getRow(3).getCell(5).setCellValue(cd.getAge());
s.getRow(4).getCell(5).setCellValue(cd.getGender());
try (FileOutputStream out = new FileOutputStream("workbook.xlsx")) {
//WorkbookEvaluator we = new WorkbookEvaluator(workbook);
workbook.write(out);
out.close();
XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) workbook);
}catch(Exception e){
System.out.println(e);
}
The Excel file format caches the result of formula evaluation, to make opening the file quicker. This means that when you're done making changes to your file, you'll need to evaluate all of the formula cells to updated their cached value. (Otherwise, when you load the file in Excel, for almost all cases it'll still show the old value until you go into that cell)
Luckily, Apache POI provides code to do that, see the Formula Evaluation documentation for details. (You can choose to only recalculate certain formulas, if you know just those cells have changed, or do everything)
For any cell, say "B5", at runtime,
cell.getReference();
will give you cell reference (like in example... it will return you "B5")
cell.getReference().toString().charAt(0);
will give you the Column Reference (will give you "B" if the current cell is B5). Now
cell.getRowIndex();
OR
cell.getReference().toString().charAt(1);
will give you Row Index. Now you have the reference of the target cell. just replace these character with the references you have already created. This will update the cell references.
The following solution worked for me
wb.setForceFormulaRecalculation(true);
// replace "wb" with your HSSFWorkbook/XSSFWorkbook object

Categories