FileOutputStream (Apachhe POI) taking too long time to save - java

When I am edit a .xlsx file using Apache poi, its taking too long to save. The .xlsx file contains, formulas formatting and freeze pane. I am using the following code,
try {
FileInputStream file = new FileInputStream(new File(path));
XSSFWorkbook fWorkbook = new XSSFWorkbook(file);
XSSFSheet fSheet = fWorkbook.getSheetAt(0);
for(int i = 0; i < jTable1.getRowCount(); i++){
if(jTable1.getModel().getValueAt(i, index1).equals("1")){
XSSFCell cell = fSheet.getRow(i+1).getCell(index1);
cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);
cell.setCellValue(new Double(1));
XSSFCellStyle cs = fWorkbook.createCellStyle();
cs.setDataFormat(fWorkbook.getCreationHelper().createDataFormat().getFormat("dd/MMMM/yyyy"));
cell =fSheet.getRow(i+1).getCell(index2);
cell.setCellValue(new Date());
cell.setCellStyle(cs);
}
}
file.close();
FileOutputStream fileOutputStream = new FileOutputStream(path);
fWorkbook.write(fileOutputStream);
fileOutputStream.close();
JOptionPane.showMessageDialog(this, "Data saved successfully.");
parent.removeContent();
}catch(Exception e){
e.printStackTrace();
}
Edit 1:
The excel file: http://ge.tt/5orGWSJ2/v/0?c
Loading Data into JTable from Excel:
try {
FileInputStream file1 = new FileInputStream(new File("c:\\sample.xlsx"));
XSSFWorkbook workbook = new XSSFWorkbook(file1);
XSSFSheet sheet = workbook.getSheetAt(0);
int rowc=sheet.getLastRowNum()+1;
int colc=sheet.getRow(0).getLastCellNum();
Object heading[] = new Object[colc+1];
XSSFRow row1 = sheet.getRow(0);
for(int i=0, column =0; i < colc; i++){
if(i == 1){
heading[column++] = "";
}
heading[column++] = cellToString(row1.getCell(i));
}
Object [][]j=new Object[rowc-1][colc+1];
for (int i = 1; i < rowc; i++) {
row1 = sheet.getRow(i);
for (int jj = 0, column = 0; jj < colc; jj++) {
if(column == 1){
j[i-1][column++] = new Boolean(false);
j[i-1][column] = cellToString(row1.getCell(jj));
}
else{
j[i-1][column]=cellToString(row1.getCell(jj));
}
column++;
}
}
jTable1.setModel(new DefaultTableModel(j, heading){
public Class getColumnClass(int columnIndex) {
if(columnIndex == 0){
return java.lang.Integer.class;
}
else if(columnIndex == 1){
return java.lang.Boolean.class;
}
else{
return java.lang.Object.class;
}
}
});
jTable1.getColumnModel().getColumn(1).setMaxWidth(60);
jTable1.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
jTable1.getTableHeader().setReorderingAllowed(false);
} catch (IOException ex) {
JOptionPane.showMessageDialog(BarcodePrint.this, ex);
}
Writing data into excel after editing column BarcodePrint:
try {
FileInputStream file = new FileInputStream(new File("c:\\sample.xlsx"));
XSSFWorkbook fWorkbook = new XSSFWorkbook(file);
XSSFCellStyle cs = fWorkbook.createCellStyle();
cs.setDataFormat(fWorkbook.getCreationHelper().createDataFormat().getFormat("dd/MMMM/yyyy"));
Date currentdate = new Date();
XSSFSheet fsheet = fWorkbook.getSheetAt(0);
Double barcodeprintstatus = new Double(1);
int newindex = 24;
int printdate = 26;
int uniqueid = 27;
for(int i = 0; i < jTable1.getModel().getRowCount(); i++){
if(jTable1.getModel().getValueAt(i, newindex).equals("1")){
for(int k=1; k < fsheet.getPhysicalNumberOfRows(); k++){
XSSFCell cell = fsheet.getRow(k).getCell(uniqueid-1);
String uid = cell.getRawValue();
if(jTable1.getModel().getValueAt(i, uniqueid).toString().equals(uid)){
cell = (fsheet.getRow(i+1)).getCell(newindex-1);
cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);
cell.setCellValue(barcodeprintstatus);
cell = fsheet.getRow(i+1).getCell(printdate-1);
cell.setCellValue(currentdate);
cell.setCellStyle(cs);
}
}
}
}
file.close();
FileOutputStream fileOutputStream = new FileOutputStream("c:\\sample.xlsx");
fWorkbook.write(fileOutputStream); // this is taking so much of time. Approximately 1 min.
fileOutputStream.close();
}catch(Exception e){
e.printStackTrace();
}
I am unable to solve this problem. fWorkbook.write(fileOutputStream); is taking so much of time as I mentioned above. Please help. Is there any other way to save the excel file? Or can I write data partially for a single column rather than the hole workbook?

Try to improve the code.
You call fSheet.getRow(i+1) twice. Try to introduce a variable and reuse the row rather than obtain it.
cell.setCellValue(new Double(1));
Create the 1 double once before the for loop and reuse it.
XSSFCellStyle cs = fWorkbook.createCellStyle();
cs.setDataFormat(fWorkbook.getCreationHelper().createDataFormat().getFormat("dd/MMMM/yyyy"));
Move the cell style creation and initializing out of the for loop. Create it before the loop and reuse.
cell.setCellValue(new Date());
Introduce a Date variable and create the Date just once. Again before the for loop.

Add a BufferedOutputStream around the FileOutputStream.

Related

How to copy a sheet from an Excel File Cell pop-up docuentation to another using POI Apache?

I am trying to copy a sheet from two different XSSF Workbooks. I have written a code that works really well (see below) but it doesn't take into account the pop-up documentation for cells and doesn't copy it (which is logical because I haven't written that functionnality).
I have searched the Apache POI documentation and it looks like there is no way to do this. Any idea on how I could do to copy-paste that information?
public class CopySheets {
public static void copySheet(String sheetName, XSSFWorkbook wbSrc,XSSFWorkbook wbDest) throws IOException {
XSSFSheet srcSheet = null;
XSSFRow srcRow = null;
XSSFCell srcCell = null;
XSSFSheet destSheet = null;
XSSFRow destRow = null;
XSSFCell destCell = null;
int fCell = 0;
int lCell = 0;
int fRow = 0;
int lRow = 0;
System.out.println(sheetName);
srcSheet = wbSrc.getSheet(sheetName);
System.out.println(srcSheet);
if (srcSheet != null) {
destSheet = wbDest.createSheet(sheetName);
fRow = srcSheet.getFirstRowNum();
lRow = srcSheet.getLastRowNum();
for (int iRow = fRow; iRow <= lRow; iRow++) {
srcRow = srcSheet.getRow(iRow);
destRow = destSheet.createRow(iRow);
if (srcRow != null) {
fCell = srcRow.getFirstCellNum();
lCell = srcRow.getLastCellNum();
for (int iCell = fCell; iCell < lCell; iCell++) {
srcCell = srcRow.getCell(iCell);
destCell = destRow.createCell(iCell);
if (srcCell != null) {
switch (srcCell.getCellTypeEnum()) {
case BLANK:
destCell.setCellValue("");
break;
case BOOLEAN:
destCell.setCellValue(srcCell.getBooleanCellValue());
break;
case ERROR:
destCell.setCellErrorValue(srcCell.getErrorCellValue());
break;
case FORMULA:
destCell.setCellFormula(srcCell.getCellFormula());
break;
case NUMERIC:
destCell.setCellValue(srcCell.getNumericCellValue());
break;
case STRING:
destCell.setCellValue(srcCell.getStringCellValue());
break;
default:
destCell.setCellFormula(srcCell.getCellFormula());
}
CellStyle origStyle = srcCell.getCellStyle(); // Or from a cell
CellStyle newStyle = wbDest.createCellStyle();
newStyle.cloneStyleFrom(origStyle);
destCell.setCellStyle(newStyle);
Comment origComment=srcCell.getCellComment();
destCell.setCellComment(origComment);
}
}
}
}
}
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("workbook.xls", true));
wbDest.write(bos);
bos.close();
}
}
Thanks a lot!
Okay, I found the answer, it turns out POI has something that enables us to get that info on the sheet as a whole so I added this bit to my code and it works like a charm!
List<XSSFDataValidation> validations=srcSheet.getDataValidations();
for (XSSFDataValidation validation:validations){
destSheet.addValidationData(validation);
}
Looking at the documentation-
http://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/Comment.html
Seems like the getAddress() method of the src Comment object will return the reference to the cell it was previously attached to (which is the src cell).
You should try creating a new Comment instead of doing
Comment origComment=srcCell.getCellComment();
destCell.setCellComment(origComment);
You should use RangeCopier.
XSSFWorkbook workbookFrom = new XSSFWorkbook(new File("/path/to/workbookFrom.xlsx"));
XSSFSheet sheetFrom = workbookFrom.getSheetAt(0);
XSSFWorkbook workbookTo = new XSSFWorkbook(new File("/path/to/workbookTo.xlsx"));
XSSFSheet sheetTo = workbookTo.createSheet("sheet1");
workbookTo.setSheetOrder("sheet1", 0);
XSSFRangeCopier xssfRangeCopier = new XSSFRangeCopier(sheetFrom, sheetTo);
//copy the row height and column width, and find the max column num
int lastRow = sheetFrom.getLastRowNum();
int lastCol = 0;
for (int i = 0; i < lastRow; i++) {
Row row = sheetFrom.getRow(i);
if (row != null) {
if (row.getLastCellNum() > lastCol) {
lastCol = row.getLastCellNum();
}
sheetTo.setDefaultRowHeight(sheetFrom.getDefaultRowHeight());
}
}
for (int j = 0; j < lastCol; j++) {
sheetTo.setColumnWidth(j, sheetFrom.getColumnWidth(j));
}
//copy contents from source sheet to destination sheet
CellRangeAddress cellAddresses = new CellRangeAddress(0, lastRow, 0, lastCol);
xssfRangeCopier.copyRange(cellAddresses, cellAddresses, true, true);
workbookTo.write(new FileOutputStream(new File("/path/to/worksheetTo.xlsx")));

How can I print the passing string row by row in excel

I am printing some string values in excel
In excel currently last string is printing, but I need to print them all row by row
Code
for(String a:arrOfStr)
{
System.out.println(a);
//CustomKeywords.'WriteExcel.demoKey'(a)
CustomKeywords.'WriteExcel.demoKey'(a)
}
keyword
#Keyword
public void demoKey(String name) throws IOException{
FileInputStream fis = new FileInputStream("C:\\Users\\lahiruh\\Katalon Studio\\Project Decypha\\Decypha data files\\Demo1.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet sheet = workbook.getSheet("Sheet1");
int rowCount = sheet.getLastRowNum()-sheet.getFirstRowNum();
Row row = sheet.createRow(rowCount+);
Cell cell = row.createCell(0);
cell.setCellType(cell.CELL_TYPE_STRING);
cell.setCellValue(name);
FileOutputStream fos = new FileOutputStream("C:\\Users\\lahiruh\\Katalon Studio\\Project Decypha\\Decypha data files\\Demo1.xlsx");
workbook.write(fos);
fos.close();
Now I can get the output like(overriding each value and giving last string )
I want to see like
Try this
for(int i = 0; i < arrOfStr.size(); i++)
{
String a = arrOfStr[i];
System.out.println(a);
//CustomKeywords.'WriteExcel.demoKey'(a)
CustomKeywords.'WriteExcel.demoKey'(a,i)
}
#Keyword
public void demoKey(String name, int index) throws IOException{
FileInputStream fis = new FileInputStream("path");
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet sheet = workbook.getSheet("Sheet1");
Row row = sheet.createRow(index + 1);
Cell cell = row.createCell(0);
cell.setCellType(cell.CELL_TYPE_STRING);
cell.setCellValue(name);
FileOutputStream fos = new FileOutputStream("path");
workbook.write(fos);
fos.close();
}
}
You have to do in the following manner.
First create a set of rows
Create cell and define the cell data type.
Store the value in the cell
I provide below the structure to store the data row by row.
int rowNumber = 0; // Row number starting with 0
for (i = 0 ; i < 10 ; i++) { //This for loop can be your data set
Row row = sheet.createRow(rowNumber++);
int columnNumber = 0; //Cell or Column number starting with 0
for (j = 0 ; j < 5 ; j++) { //This for loop can be your data set
Cell cell = row.createCell(columnNumber++);
cell.setCellValue("Some string value");
}
}

Update excel using Java

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)
}

upload large .xlsx file in gui java

i have a large excel file containing 600.000 rows , i used XSSFWorkbook to upload the excel file at a Jtable in my GUI but it takes about 15 minutes to be done in eclipse and once i export my project to a jar file i can't do it even in the 15 minutes . Any help please ?
Here is the method , that i found in internet to upload my excel file .
void fillData(File file) {
int index = -1;
XSSFWorkbook workbook = null;
try {
try {
String f = file.getPath();
File file1 = new File(f);
OPCPackage opcPackage = OPCPackage.open(file1);
workbook = new XSSFWorkbook(opcPackage);
} catch (IOException ex) {
Logger.getLogger(ProjectApp3.class.getName()).log(Level.SEVERE, null, ex);
}
String[] strs = new String[workbook.getNumberOfSheets()];
//get all sheet names from selected workbook
for (int i = 0; i < strs.length; i++) {
strs[i] = workbook.getSheetName(i);
}
JFrame frame = new JFrame("Input Dialog");
//select sheet
String selectedsheet = (String) JOptionPane.showInputDialog(
frame, "Which worksheet you want to import ?", "Select Worksheet",
JOptionPane.QUESTION_MESSAGE, null, strs, strs[0]);
if (selectedsheet != null) {
for (int i = 0; i < strs.length; i++) {
if (workbook.getSheetName(i).equalsIgnoreCase(selectedsheet))
index = i;
}
XSSFSheet sheet = workbook.getSheetAt(index);
XSSFRow row = sheet.getRow(0);
//import headers data
headers.clear();
for (int i = 0; i < row.getLastCellNum(); i++) {
XSSFCell cell1 = row.getCell(i);
headers.add(cell1.toString());
}
//import data
data1.clear();
for (int j = 1; j < sheet.getLastRowNum() + 1; j++) {
Vector d = new Vector();
row = sheet.getRow(j);
int noofrows = row.getLastCellNum();
for (int i = 0; i < noofrows; i++) { //To handle empty excel cells
XSSFCell cell = row.getCell(i,
org.apache.poi.ss.usermodel.Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
d.add(cell.toString());
}
d.add("\n");
data1.add(d);
}
} else {
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
I think the basic problem is that you're trying to give. your Jtable all the data at startup. This is going to be deeply problematic. You may want to write a custom subclass from AbstractTableModel. See the docs for Jtable that includes this:
TableModel dataModel = new AbstractTableModel() {
public int getColumnCount() { return 10; }
public int getRowCount() { return 10;}
public Object getValueAt(int row, int col) { return new Integer(row*col); }
};
JTable table = new JTable(dataModel);
JScrollPane scrollpane = new JScrollPane(table);
You can implement those three methods based on the info that POI gives you. But do lazy loading of the data, most especially for getValueAt(). Keep the spreadsheet file open and grab the data only when the user scrolls to view it.

Why can't set a value for a row and column with the Apache POI?

I need to set a value for a specific row and column of the spreadsheet, but I get a null pointer before even i = 1. I've tried changing the code but this error keeps happening and I have no more idea why.Does anyone have any idea why this happens?
My code
public Workbook build(Planilha planilha) {
File file = new File(TEMPLATE_PATH);
if (!file.exists()) {
Log.error(this, String.format("File %s not exists.", file.getAbsolutePath()));
throw new NotFoundException("File not exists.");
}
Workbook wb = null;
try (FileInputStream fs = new FileInputStream(file)) {
wb = new XSSFWorkbook(fs);
wb = writeMetadatas(planilha, wb);
Map<String, Integer> header = getHeader(wb);
Sheet sheet = wb.getSheetAt(0);
Row row;
Cell cell;
for (int i = 0; i <= 10; i++) {
row = sheet.getRow(i);
for (int j = 0; j <= 10; j++) {
cell = row.getCell(j, Row.CREATE_NULL_AS_BLANK);
if (cell.getColumnIndex() == 0 && row.getRowNum() == 7) {
cell.setCellValue("teste");
}
}
}
} catch (Exception e) {
Log.error(this, "Erro: Planilha não existe", e);
System.err.print("Erro");
}
String tmpDir = System.getProperty("java.io.tmpdir");
File f = FileUtil.file(PATH, System.currentTimeMillis() + ".xlsx");
try {
FileOutputStream fout = new FileOutputStream(f);
wb.write(fout);
fout.flush();
fout.close();
} catch (Exception e) {
Log.error(this, "Erro ao abrir arquivo p escrever.");
}
return wb;
}
**NullPointer happens in cell.setCellValue("teste");
I'm trying to set that cell
First, you can test if the row number is a certain number outside of your for loop that loops over the cells in a row. Pull that if outside your j for loop.
It looks like the Cell doesn't exist. row.getCell(j) is returning null.
You can use a MissingCellPolicy to determine whether you want to return a new Cell if the Cell doesn't already exist. The CREATE_NULL_AS_BLANK value will create a blank Cell for you if it doesn't already exist.

Categories