I'm trying to create a .xlsx file using XSSFWorkBook in Java.
Using below code I'm trying
try
{
File tempFile = new File(validateFileUrl);
XSSFWorkbook workbook = null;
XSSFSheet sheet = null;
if(!rowList.isEmpty()) // rowList contains comma(,) separated string values
{
workbook = new XSSFWorkbook();
sheet = workbook.createSheet();
int rownum=0;
for(String rowStr : rowList)
{
XSSFRow row = sheet.createRow(rownum++);
String[] cellArr = rowStr.split(",");
int cellCount=0;
for(String cellStr : cellArr)
{
XSSFCell crrCell = row.createCell(cellCount++);
crrCell.setCellValue(cellStr);
}
}
FileOutputStream fos = new FileOutputStream(tempFile);
workbook.write(fos);
workbook.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
file got created successfully, but the problem is that created file is opening in Read only mode, How can I create this in writeable mode?
I have tried the below option also
tempFile.setWritable(true);
but its not working, please help on this. Thanks
Excel will not allow editing a file that some other application is still writing. Instead it is waiting for exclusive access.
You need to ensure in Java the file buffer gets closed when you are finished writing the file. This happens either when the JVM terminates or when your code explicitly closes the FileOutputStream. Note that explicitly calling close can be tricky in case exceptions get thrown. Here is a safe way that makes use of the AutoClose feature of FileOutputStream:
try {
File tempFile = new File(validateFileUrl);
XSSFWorkbook workbook = null;
XSSFSheet sheet = null;
if(!rowList.isEmpty()) { // rowList contains comma(,) separated string values
workbook = new XSSFWorkbook();
sheet = workbook.createSheet();
int rownum=0;
for(String rowStr : rowList) {
XSSFRow row = sheet.createRow(rownum++);
String[] cellArr = rowStr.split(",");
int cellCount=0;
for(String cellStr : cellArr) {
XSSFCell crrCell = row.createCell(cellCount++);
crrCell.setCellValue(cellStr);
}
}
try (FileOutputStream fos = new FileOutputStream(tempFile)) {
workbook.write(fos);
}
workbook.close();
}
}
catch(Exception e) {
e.printStackTrace();
}
Note that vice versa, Excel is exclusively holding access to the file. So if you want to write it again from your application, ensure Excel has closed the document.
Fix is to close the FileOutputStream object
fos.close();
Sample Code:
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.List;
public class Excel {
public static void main(String[] args) {
String validateFileUrl = "so-excel.xlsx";
List<String> rowList = Arrays.asList("1", "2");
try
{
File tempFile = new File(validateFileUrl);
XSSFWorkbook workbook = null;
XSSFSheet sheet = null;
if(!rowList.isEmpty()) // rowList contains comma(,) separated string values
{
workbook = new XSSFWorkbook();
sheet = workbook.createSheet();
int rownum=0;
for(String rowStr : rowList)
{
XSSFRow row = sheet.createRow(rownum++);
String[] cellArr = rowStr.split(",");
int cellCount=0;
for(String cellStr : cellArr)
{
XSSFCell crrCell = row.createCell(cellCount++);
crrCell.setCellValue(cellStr);
}
}
FileOutputStream fos = new FileOutputStream(tempFile);
workbook.write(fos);
System.out.println("Workbook created!!");
workbook.close();
fos.close(); //To close the FileOutputStream object
System.out.println("File Output Stream closed!!");
}
Thread.currentThread().sleep(600000);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Related
I am iterating through a list of data which I am sending from the runner file(FunctionVerifier.java).
When I am calling the function writeExcel() in excelHandler.java it is entering only the last data from the list that I am iterating through.
Can someone please let me know the reason and how to fix this
public void writeExcel(String sheetName, int r, int c, String data) throws IOException {
file = new FileInputStream(new File(inFilePath));
wb = new XSSFWorkbook(file);
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.createRow(r);
row.createCell(c).setCellValue(data);
closeExcelInstance();
FileOutputStream outputStream = new FileOutputStream(inFilePath);
wb.write(outputStream);
wb.close();
outputStream.close();
}
public void closeExcelInstance() {
try {
file.close();
} catch (Exception e) {
System.out.println(e);
}
}
FunctionVerifier.java
package Sterling.oms;
import Sterling.oms.Process.CouponValidationProcess;
import Sterling.oms.Utilities.ExcelHandler;
import java.util.ArrayList;
public class FuncVerify {
public static void main(String args[]) throws Exception {
String filePath = System.getProperty("user.dir") + "/src/test/resources/TestData/test.xlsx";
ExcelHandler excelHandler = new ExcelHandler(filePath);
excelHandler.readExcelData("Validation");
CouponValidationProcess couponValidationProcess = new CouponValidationProcess("OMS-T781");
excelHandler.createSheet();
// couponValidationProcess.enterValidationHeaderRowInExcel(filePath);
String sheet = "ValidationData";
if (excelHandler.getRowCountWhenNull(sheet) < 1) {
ArrayList<String> header = new ArrayList<>();
header.add("Test Case");
header.add("Coupon ID");
header.add("Grand Total");
header.add("Manual Grand Total");
for (int i = 0; i < header.size(); i++) {
// excelHandler = new ExcelHandler(filePath);
excelHandler.writeExcel(sheet, 0, i, header.get(i));
// excelHandler.closeExcelInstance();
}
}
}
}
The reason for only storing the last item is that Sheet.createRow as well as Row.createCell are doing exactly what their method names tell. They create a new empty row or cell each time they get called. So every times Row row = sh.createRow(r) gets called, it creates a new empty row at row index r and looses all former created cells in that row.
The correct way to use rows would be first trying to get the row from the sheet. And only if it is not present (null), then create a new row. The same is for cells in rows. First try to get them. And only if not present, then create them.
...
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.getRow(r); if (row == null) row = sh.createRow(r);
Cell cell = row.getCell(c); if (cell == null) cell = row.createCell(c);
cell.setCellValue(data);
...
That's the answer to your current question.
But the whole approach, to open the Excel file to create a Workbook, then set data of only one cell in and then write the whole workbook out to the file, and doing this for each cell, is very sub optimal. Instead the workbook should be opened, then all known new cell values should be set into the sheet and then the workbook should be written out.
Your approach is wrong, you open your files again for each line you want to write to Excel, then save again. You just have to create one FileInputStream and send it to your Workbook where you do all your Excel work. After you have finished writing all your lines, you can create only one FileOutputStream and export your changes in your Workbook to a file of your choice.
writeExcel()
public void writeExcel(String sheetName, int r, int c, ArrayList<String> data) throws IOException {
file = new FileInputStream(new File(inFilePath));
wb = new XSSFWorkbook(file);
Sheet sh;
sh = wb.getSheet(sheetName);
Row row = sh.createRow(r);
//Adding data column wise
for (String h : data) {
row.createCell(c++).setCellValue(h);
}
closeExcelInstance();
FileOutputStream outputStream = new FileOutputStream(inFilePath);
wb.write(outputStream);
wb.close();
outputStream.close();
}
I would like to delete a column in Excel (XLSX) with the Apache POI 5.0.0. I want to use the shiftColumns method, so affected formulas get adjusted automatically.
void shiftColumns(int startColumn, int endColumn, int n)
https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/Sheet.html
The documentation says that, if you want to shift left (overriding columns on the left side), you should use a negative number.
I tried the following example on the following Excel file:
String path = "pathOfTheExcelFile";
File file = new File(path);
Workbook wb = null;
try (FileInputStream inputStream = new FileInputStream(file)) {
wb = WorkbookFactory.create(inputStream); // read workbook
} catch (IOException e) {
e.printStackTrace();
}
if(wb == null)
return;
Sheet sheet = wb.getSheetAt(0); // read first sheet
// deleting / overriding 2nd column
sheet.shiftColumns(2, 5, -1); // shifting from 3rd to last column to the left
try (OutputStream fileOut = new FileOutputStream(path)) {
wb.write(fileOut); // writing the result in the Excel file (ERROR)
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (wb != null)
wb.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
Excel file I want to alter:
After executing the code, I get this error on line wb.write(fileOut);:
java.lang.IndexOutOfBoundsException
at org.apache.xmlbeans.impl.store.Xobj.removeElement(Xobj.java:2099)
at org.apache.xmlbeans.impl.store.Xobj.remove_element(Xobj.java:2130)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl.removeC(CTRowImpl.java:173)
at org.apache.poi.xssf.usermodel.XSSFRow.fixupCTCells(XSSFRow.java:612)
at org.apache.poi.xssf.usermodel.XSSFRow.onDocumentWrite(XSSFRow.java:582)
at org.apache.poi.xssf.usermodel.XSSFSheet.write(XSSFSheet.java:3625)
at org.apache.poi.xssf.usermodel.XSSFSheet.commit(XSSFSheet.java:3570)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:465)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:470)
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:221)
at test.App.main(App.java:38)
FYI, I use Java 11 and these libraries:
libraries
After execution, my file has 0KB.
I debugged into the Apache POI library while saving the workbook in the Excel file. This is where the problem starts. Maybe it helps you:
pic1
pic2
pic3
Yes, here are still problems in Sheet.shiftColumns even in latest version Apache POI 5.1.0. The shiftColumns does not removing the cells properly when negative shifted. That's why the error while writing then.
If you explicitly remove the cells of the column you want over-shfting, then the error is gone. So we need to remove all cells from second column (index 1) before shifting third column (index 2) to left.
But there are additional problems too. Even the last version does not update the calculation chain while shifting formulas. This is the problem of this Q/A: shiftColumn method is not working when cell has formula.
Complete example:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import java.lang.reflect.Method;
public class ExcelShiftColums {
private static void removeCalcChain(XSSFWorkbook workbook) throws Exception {
CalculationChain calcchain = workbook.getCalculationChain();
Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class);
removeRelation.setAccessible(true);
removeRelation.invoke(workbook, calcchain);
}
private static void removeColumn(Sheet sheet, int column) {
for (Row row : sheet) {
Cell cell = row.getCell(column);
if (cell != null) {
row.removeCell(cell);
}
}
}
private static int getLastFilledColumn(Sheet sheet) {
int result = 0;
for (Row row : sheet) {
if (row.getLastCellNum() > result) result = row.getLastCellNum();
}
return result;
}
public static void main(String[] args) throws Exception {
String inFilePath = "./ExcelExampleIn.xlsx"; String outFilePath = "./ExcelExampleOut.xlsx";
//String inFilePath = "./ExcelExampleIn.xls"; String outFilePath = "./ExcelExampleOut.xls";
try (Workbook workbook = WorkbookFactory.create(new FileInputStream(inFilePath));
FileOutputStream out = new FileOutputStream(outFilePath ) ) {
Sheet sheet = workbook.getSheetAt(0);
int lastFilledColumn = getLastFilledColumn(sheet);
removeColumn(sheet, 1);
sheet.shiftColumns(2, lastFilledColumn, -1);
if (workbook instanceof XSSFWorkbook) removeCalcChain((XSSFWorkbook)workbook);
workbook.write(out);
}
}
}
I am trying to write a program where I have to either
create an exel file and insert a table (and eventually data) into it, OR
duplicate a template exel file that I have made, and copy that over to a new directory to use.
I have gotten the 'duplicate' part working, but I cannot open the duplicated file (It says the file format/extension is not valid).
This is the code:
try {
var template = new RandomAccessFile(App.NAME+".xlsx", "rw");
var copy = new RandomAccessFile(App.data.getFilePath()+App.NAME+".xlsx", "rw");
var sourceChannel = template.getChannel();
var destinationChannel = copy.getChannel();
destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
System.out.println("Successfully created exel file");
} catch (IOException e) {
System.err.println("Error creating exel file: " + e.getMessage());
}
Does anyone know what I should do to fix this?
Thanks in advance.
The following example creates an Excel File named example.xls. The file has a table with two columns ( name, job ) and one row (bayrem, developer).
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Persons");
sheet.setColumnWidth(0, 6000); //style
sheet.setColumnWidth(1, 4000);//style
Row header = sheet.createRow(0);
CellStyle headerStyle = workbook.createCellStyle();//style
headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());//style
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//style
XSSFFont font = ((XSSFWorkbook) workbook).createFont();//style
font.setFontName("Arial");//style
font.setFontHeightInPoints((short) 16);//style
font.setBold(true);//style
headerStyle.setFont(font);//style
Cell headerCell = header.createCell(0);
headerCell.setCellValue("Name");
headerCell.setCellStyle(headerStyle);//style
headerCell = header.createCell(1);
headerCell.setCellValue("Job");
headerCell.setCellStyle(headerStyle);//style
CellStyle style = workbook.createCellStyle();//style
style.setWrapText(true);//style
Row row = sheet.createRow(2);
Cell cell = row.createCell(0);
cell.setCellValue("Bayrem");
cell.setCellStyle(style);//style
cell = row.createCell(1);
cell.setCellValue("Developer");
cell.setCellStyle(style);//style
File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + "example.xlsx";
FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
workbook.close();
This is all you need for a copy, the language level has to be 7 or higher
import java.io.IOException;
import java.nio.file.*;
public class ExcelCopy {
public static void main(String[] args) {
FileSystem system = FileSystems.getDefault();
Path original = system.getPath("C:\\etc\\etc\\Desktop\\ExcelTestOne.xlsx");
Path target = system.getPath("C:\\etc\\etc\\Desktop\\ExcelCopy.xlsx");
try {
// Throws an exception if the original file is not found.
Files.copy(original, target, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
System.out.println("ERROR");
}
}
}
original post is here,I check that it worked for you.
How to copy excel file?
I need to create a file .csv with apache-poi but this file is empty. For this example I want to create only header about this file so I do:
public byte[]...(File save_file) {
Workbook workbook = null;
Sheet sheet = null;
FileOutputStream outputStream=null;
try {
workbook = new HSSFWorkbook();
sheet = workbook.createSheet();
createHeader(0,sheet);
outputStream = new FileOutputStream(save_file);
workbook.write(outputStream);
} catch (Exception exception) {
log.error("ERROR", exception);
} finally {
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.writeTo(outputStream);
log.info("SOTTO BYTE "+byteArrayOutputStream.toByteArray().length);
return byteArrayOutputStream.toByteArray();
}
and after the method "create_header":
private static void createHeader(int rowPosition,Sheet sheet) {
Row row = sheet.createRow(rowPosition);
Cell cell = row.createCell(1);
cell.setCellValue("DATE");
cell = row.createCell(2);
cell.setCellValue("EMAIL");
}
The problem is the file is empty. In the first method I need to return the byte[] that represents the csv file. Anyone can help me?
I am trying to create one read only Excel-sheet using Apache POI 3.10.
private void lockAll(Sheet s, String password) throws Exception{
XSSFSheet sheet = ((XSSFSheet)s);
sheet.protectSheet(password);
sheet.enableLocking();
sheet.lockSelectLockedCells();
sheet.lockSelectUnlockedCells();
}
Now I am calling this method after creating my excel sheet using following.
private String generateExcel(List<Model> DataList) {
Workbook wwbook = null;
File ff = null;
try {
String filePath = // getting this path using ServletContext.
wwbook = new XSSFWorkbook();
Sheet wsheet = wwbook.createSheet("MyReport");
ApachePoiExcelFormat xlsxExcelFormat = new ApachePoiExcelFormat();
CellStyle sheetHeading = xlsxExcelFormat.SheetHeading(wwbook);
//My personal org.apache.poi.ss.usermodel.CellStyle here.
short col = 0, row = 0;
XSSFRow hrow = (XSSFRow) (XSSFRow) wsheet.createRow(row);
XSSFCell cell = hrow.createCell(col);
//My code here to iterate List and add data to cell.
FileOutputStream fileOut = new FileOutputStream(filePath.toString());
wwbook.write(fileOut);
lockAll(wsheet, "password"); //******calling the method to lock my sheet.
fileOut.close();
System.out.println("Excel Created");
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return filePath;
}
Now while I am running this code to download the excel file. Then I am getting error on the webpage but not on my eclipse console.
Next I was trying to run the same code after commenting the following line in lockAll method. And then the excel downloading happens as required, but every cells in the sheet are editable.
sheet.protectSheet(password);