I am trying to update an existing .XLSM file using Apache POI. Every time I run my code I receive an error as shown below.
Exception in thread "main" java.lang.IllegalArgumentException: Attempting to write a row[1] in the range [0,9] that is already written to disk.
at org.apache.poi.xssf.streaming.SXSSFSheet.createRow(SXSSFSheet.java:136)
at com.log.test.Test.main(Test.java:41)
Basically I wanted to use a macro enabled excel file as standard template , using java code i wanted to make a copy of template and update the some sheet's columns data and save the file.
I am trying with below sample code :
OPCPackage pkg = OPCPackage.open(new File("C:/LogTest/testme.xlsm"));
XSSFWorkbook wb_template;
wb_template = new XSSFWorkbook(pkg);
System.out.println("package loaded");
SXSSFWorkbook wb = new SXSSFWorkbook(wb_template);
wb.setCompressTempFiles(true);
SXSSFSheet sh = (SXSSFSheet) wb.getSheet("Asset Names");
sh.setRandomAccessWindowSize(100);
for (int rownum = 1; rownum < 10; rownum++) {
Row row = sh.createRow(rownum);
for (int cellnum = 0; cellnum < 2; cellnum++) {
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue("hello");
}
}
FileOutputStream out = new FileOutputStream(new File("C:/output/new.xlsm"));
wb.write(out);
out.close();
wb.dispose();
System.out.println("Done !!!");
Can this be achieved using Apache POI ? or i need to use some other libraries ?
sample template
Related
I am using the Apache POI library to export data to Excel. I have tried all the latest versions (3.17, 4.1.2, and 5.2.1).
I have a problem with Excel 97 (.xls) format in relation to cell styles. The cell style somehow is lost (or not displayed) after a certain number of columns.
Here is my sample code:
private void exportXls() {
try (
OutputStream os = new FileOutputStream("test.xls");
Workbook wb = new HSSFWorkbook();) {
Sheet sh = wb.createSheet("test");
Row r = sh.createRow(0);
for (int i = 0; i < 50; i++) {
Cell c = r.createCell(i);
c.setCellValue(i + 1);
CellStyle cs = wb.createCellStyle();
cs.setFillBackgroundColor(IndexedColors.WHITE.index);
cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cs.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
c.setCellStyle(cs);
}
wb.write(os);
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
And the result as viewed by MS Excel 2019
Viewed by MS Excel
As you can see, the style/format is lost after cell 43rd.
But, when I open the same file by other applications like XLS Viewer Free (from Microsoft Store) or Google Sheets (online), the style/format still exists and is displayed well.
Viewed by XLS Viewer Free
Viewed by Google Sheets
Could anyone please tell me what is going on here?
Did I miss something in my code?
Is there any hidden setting in MS Excel that causes this problem?
Thank you.
Creating cell styles for each single cell is not a good idea using apache poi. Cell styles are stored on workbook level in Excel. The sheets and cells share the cell styles if possible.
And there are limits for maximum count of different cell styles in all Excel versions. The limit for the binary *.xls is less than the one for the OOXML *.xlsx.
The limit alone cannot be the only reason for the result you have. But it seems as if Excel is not very happy with the 50 exactly same cell styles in workbook. Those are memory waste as only one shared style would be necessary as all the 50 cells share the same style.
Solutions are:
Do creating the cell styles on workbook level outside cell creating loops and only set the styles to the cells in the loop.
Example:
private static void exportXlsCorrect() {
try (
OutputStream os = new FileOutputStream("testCorrect.xls");
Workbook wb = new HSSFWorkbook();) {
CellStyle cs = wb.createCellStyle();
cs.setFillBackgroundColor(IndexedColors.WHITE.index);
cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cs.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
Sheet sh = wb.createSheet("test");
Row r = sh.createRow(0);
for (int i = 0; i < 50; i++) {
Cell c = r.createCell(i);
c.setCellValue(i + 1);
c.setCellStyle(cs);
}
wb.write(os);
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
Sometimes it is not really possible to know all possible needed cell styles before creating the cells. Then CellUtil can be used. This has a method CellUtil.setCellStyleProperties which is able to set specific style properties to cells. Doing that new cell styles are created on workbook level only if needed. If already present, the present cell styles are used.
Example:
private static void exportXlsUsingCellUtil() {
try (
OutputStream os = new FileOutputStream("testUsingCellUtil.xls");
Workbook wb = new HSSFWorkbook();) {
Sheet sh = wb.createSheet("test");
Row r = sh.createRow(0);
for (int i = 0; i < 50; i++) {
Cell c = r.createCell(i);
c.setCellValue(i + 1);
java.util.Map<java.lang.String,java.lang.Object> properties = new java.util.HashMap<java.lang.String,java.lang.Object>();
properties.put(org.apache.poi.ss.util.CellUtil.FILL_BACKGROUND_COLOR, IndexedColors.WHITE.index);
properties.put(org.apache.poi.ss.util.CellUtil.FILL_FOREGROUND_COLOR, IndexedColors.LIGHT_BLUE.getIndex());
properties.put(org.apache.poi.ss.util.CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
org.apache.poi.ss.util.CellUtil.setCellStyleProperties(c, properties);
}
wb.write(os);
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
I want to export huge data to excel file quickly. Currently, I am using Apache POI for exporting excel file but it takes a lot of time in iteration for writing data to each row.
I am trying to write more than 40,000 rows to excel but it takes more than 10 mins to generate the file.
I am using SXSSFWorkbook and also using an iterator to remove the list element after writing it to row to minimise the memory issue.
Below is my code
public ByteArrayInputStream generateExcel(String fromDate, String toDate, String locationType, String locationId) throws IOException, ParseException {
String[] columns = new String[]{"Role", "Name", "Phone Number", "ETC.."};
SXSSFWorkbook wb = new SXSSFWorkbook(SXSSFWorkbook.DEFAULT_WINDOW_SIZE/* 100 */);
wb.setCompressTempFiles(true);
SXSSFSheet sh = wb.createSheet("Personal Details");
sh.setRandomAccessWindowSize(100);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Font headerFont = wb.createFont();
headerFont.setBold(true);
headerFont.setColor(IndexedColors.BLUE.getIndex());
CellStyle headerCellStyle = wb.createCellStyle();
headerCellStyle.setFont(headerFont);
// Row for Header
Row headerRow = sh.createRow(0);
// Header
for (int col = 0; col < columns.length; col++) {
Cell cell = headerRow.createCell(col);
cell.setCellValue(columns[col]);
cell.setCellStyle(headerCellStyle);
}
// Fetch Data From MongoDB
List<User> farmerList = userRepo.getFarmerList(fromDate, toDate, locationId);
int rowIdx = 1;
Iterator<User> i = farmerList.iterator();
while (i.hasNext()) {
User farmer = i.next();
SXSSFRow row = sh.createRow(rowIdx++);
row.createCell(0).setCellValue(getUserMainRole(farmer));
row.createCell(1).setCellValue(farmer.getFirstName() + " " + farmer.getLastName());
row.createCell(2).setCellValue(farmer.getPrimaryPhone());
row.createCell(3).setCellValue(agentName);
i.remove();
}
wb.write(out);
out.close();
return new ByteArrayInputStream(out.toByteArray());
}
I want to improve the speed of two things:
Fetching Data from MongoDB: I am using indexing
Improve speed of iterator
Can anyone suggest me a better way to do this or if there is another way of generating excel file?
I Have a data stored in variables and then i want to write my data to excel file(.xlsx).
(i.e) I use automation testing tools like selenium to get data from webpage and i store it in variable which i want to wrie in xlsx file
After a lot of google search I found many of users uses list or objects to write into .xlsx file.
I created a list and add my variable to that list and using looping statements (for loop) i checked whether my data is stored in list by printing it.
Then I created XSSFWorkbook and XSSFSheet and XSSFRow and XSSFCell to write data.
I write a cell by using setCellValue method to my cell.
My code successfully creates a xlsx file and sheet in it
but after execution i could not able to find any data in it.
Source code:
ArrayList<String> head = new ArrayList<String>();
head.add("Register Number");
head.add(subject1);
head.add(subject2); //subject1 and subject2 are variable i created
System.out.println(head.get(1)); //To check if my list has value
XSSFWorkbook workbook = new XSSFWorkbook();
FileOutputStream fileOut = new FileOutputStream("/home/st.xlsx");
for (int i = 0; i < head.size(); i++)
{
XSSFRow Row = sheet1.createRow(1);
XSSFCell cell = Row.createCell(1);
cell.setCellValue(head.get(1));
sheet1.autoSizeColumn(1);
}
workbook.write(fileOut);
fileOut.close();
I expect my code add data to my file.
Main thing is During execution when i try to open my .xlsx file it has data in it.
But after the complete execution i get with the empty xlsx file.
I don't know why i'm getting this and What wrong in my code?
Thanks in advance!
ArrayList<String> head = new ArrayList<String>();
head.add("Register Number");
head.add(subject1);
head.add(subject2); // subject1 and subject2 are variable i created
System.out.println(head.get(0)); // To check if my list has value
System.out.println(head.get(1)); // To check if my list has value
System.out.println(head.get(2)); // To check if my list has value
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet1 = wb.createSheet("Sheet1");
for (int r = 0; r < head.size(); r++)
{
XSSFRow row = sheet1.createRow(r);
XSSFCell cell = row.createCell(0);
cell.setCellValue(head.get(r));
sheet1.autoSizeColumn(0);
}
// Write this workbook to a FileOutputStream.
FileOutputStream fileOut = new FileOutputStream("/home/st.xlsx");
workbook.write(fileOut);
fileOut.flush();
fileOut.close();
More info here:
https://gist.github.com/madan712/3912272
I am writing a small utility that creates a pivot table in an excel sheet using POI and I want to read the data from the pivot table back to the program which will save it as a PDF file using Itext. I am running into a problem where the program cannot read the data from the pivot table after it is created. The program only can "see" the information in the pivot table after I manually open the created file and hit the save button in excel. Does anyone know a way to read the data from the pivot table from the XSSFPivotTable object or otherwise force a way for the file to "save" so it can be accessed by the program again?
Here is a snippet of code so you can see what I'm talking about. I'm a student so any advice on best practices would be greatly appreciated as well.
public void returnPivotData() throws IOException {
FileInputStream fs = new FileInputStream(this.xlsxFile);
XSSFWorkbook book = new XSSFWorkbook(fs);
XSSFSheet dataSheet = book.getSheet("Sheet1");
AreaReference dataRef = new AreaReference("A1:E15",
SpreadsheetVersion.EXCEL2007);
XSSFPivotTable table = dataSheet.createPivotTable(dataRef,
new CellReference("A16"));
table.addRowLabel(0);
table.addColumnLabel(DataConsolidateFunction.SUM, 3);
// Save the data back to the file
FileOutputStream fsOut = new FileOutputStream(
"D:\\workspace\\test.xlsx");
book.write(fsOut);
fsOut.close();
book.close();
fs.close();
// This does not allow access
FileInputStream fsIn = new FileInputStream("D:\\workspace\\test.xlsx");
XSSFWorkbook bookNew = new XSSFWorkbook(fsIn);
XSSFSheet sheet = bookNew.getSheet("Sheet1");
for (int i = 0; i < 20; i++) {
XSSFRow rowNew = sheet.getRow(i);
XSSFCell cellNew = rowNew.getCell(0,
MissingCellPolicy.CREATE_NULL_AS_BLANK);
System.out.println(cellNew.toString());
}
fsIn.close();
bookNew.close();
}
I want to read and write large excel files. Therefore, I used SXSSFWorkbook to write the excel file and XSSF and SAX EVENT API to read the files.
However, the cell content is empty when the excel file is read, and if the excel file is written using SXSSFWOrkbook. If I open the written excel file and save it again, the content is shown correctly.
The following is the code I used to write the excel file.
SXSSFWorkbook wb = new SXSSFWorkbook();
wb.setCompressTempFiles(true);
SXSSFSheet sh = (SXSSFSheet) wb.createSheet();
// sh.setRandomAccessWindowSize(100);// keep 100 rows in memory,
// exceeding rows will be flushed to disk
for (int rownum = 0; rownum < 100; rownum++) {
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);
}
}
FileOutputStream out = new FileOutputStream("D:\\tempsxssf.xlsx");
wb.write(out);
out.flush();
out.close();
wb.dispose();
I am in a big trouble, can someone help me to figure out the issue?
I used another constructor according POI documentation
SXSSFWorkbook(workbook, rowAccessWindowSize, compressTmpFiles, useSharedStringsTable)
Like this:
SXSSFWorkbook workbook = new SXSSFWorkbook(null, 1000, true, true);
where you can enable shared strings table