I am opening an Excel file (the source) in Java using an Apache POI Workbook, altering data in a certain set of cells, saving the Workbook to a separate file, then closing the Workbook (because the documentation states to close the Workbook, even if it is read-only).
POI alters the data in the source Excel file every time. I have tried a few different methods to prevent this according to recommendations from the POI documentation, but these methods fail.
Here are two attempts that should work in theory, but do not.
Attempt 1 - set the source file to read only
File file = new File("{path-to-existing-source-file}");
file.setReadOnly();
Workbook workbook = WorkbookFactory.create(file); // throws a FileNotFoundException
A FileNotFoundException for "Access is denied" is thrown at WorkbookFactory.create(file):
java.io.FileNotFoundException: {path-to-source-file-that-exists} (Access is denied)
at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(RandomAccessFile.java:316)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:243)
at org.apache.poi.poifs.nio.FileBackedDataSource.newSrcFile(FileBackedDataSource.java:158)
at org.apache.poi.poifs.nio.FileBackedDataSource.<init>(FileBackedDataSource.java:60)
at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:224)
at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:172)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:298)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:271)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:252)
at com.stackoverflow.MyClass(MyClass.java:71)
The source file exists, and it is validly read-only.
Attempt 2 - use the POI API constructor which allows read-only to be explicitly set
File file = new File("{path-to-existing-source-file}");
Workbook workbook = WorkbookFactory.create(file, null, true); // true is read-only
// dataBean is just a container bean with the appropriate reference values
Sheet sheet = workbook.getSheet(dataBean.getSheetName());
Row row = sheet.getRow(dataBean.getRowNumber());
Cell cell = row.getCell(dataBean.getColumnNumber());
cell.setCellValue(dataBean.getValue());
// target is another File reference
OutputStream outStream = new FileOutputStream(new File("path-to-target-file"));
workbook.write(outStream); // throws InvalidOperationException
An InvalidOperationException is thrown during the write call:
Caused by: org.apache.poi.openxml4j.exceptions.InvalidOperationException:
Operation not allowed, document open in read only mode!
at org.apache.poi.openxml4j.opc.OPCPackage.throwExceptionIfReadOnly(OPCPackage.java:551)
at org.apache.poi.openxml4j.opc.OPCPackage.removePart(OPCPackage.java:955)
at org.apache.poi.openxml4j.opc.PackagePart.getOutputStream(PackagePart.java:531)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.commit(XSSFWorkbook.java:1770)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:463)
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:236)
at com.stackoverflow.MyClass(MyClass.java:90)
"Operation not allowed, document open in read only mode!". Of course it is set to read-only; I don't want the source written to, I just want all the data to go to a new target.
What can I set or change to not alter the source when using POI?
Our current workaround is to create a duplicate source file, but that is not a good solution.
I had the same problem and solved it by using a FileInputStream instead of a File.
Workbook workbook = WorkbookFactory.create(file);
becomes:
Workbook workbook = WorkbookFactory.create(new FileInputStream(file));
You need to have two workbooks, one where you get the datafrom (read) and another one you write to.
Look man, this is how I did a few months ago, please notice that I use .write() on the second workbook (hssfWorkbookNew), not the one im using to read the data from, read it carefully. This code is just for getting first sheet of a XLS excel and copying it to a new file.
// this method generates a new excelFile based on the excelFile he receives
public void generarXLS(File excelFile, File excelNewFile) {
InputStream excelStream = null;
OutputStream excelNewOutputStream = null;
try {
excelStream = new FileInputStream(excelFile);
excelNewOutputStream = new FileOutputStream(excelNewFile);
// Representation of highest level of excel sheet.
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(excelStream);
HSSFWorkbook hssfWorkbookNew = new HSSFWorkbook();
// Chose the sheet that we pass as parameter.
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(0);
// Create new sheet we are gonna use.
HSSFSheet hssfSheetNew = hssfWorkbookNew.createSheet("Copy-Copia");
// Create new sheet where we will copy the data
// Object that allow us to read a row from the sheet and extract the data from the cells
HSSFRow hssfRow;
HSSFRow hssfRowNew; // for hssfSheetNew
// Initialize the object that reads value of cell
HSSFCell cellNew;
// Get number of rows of the sheet
int rows = hssfSheet.getLastRowNum();
String cellValue;
// Style of the cell border, color background and pattern (fill pattern) used.
CellStyle style = hssfWorkbookNew.createCellStyle();
// Definition of the font of the cell.
// Iterate trhough all rows to get the cells and copy them to the new sheet
for (Row row : hssfSheet) {
hssfRowNew = hssfSheetNew.createRow(row.getRowNum());
if (row.getRowNum() > 999999) {
break;
}
for (Cell cell : row) {
cellValue = (cell.getCellType() == CellType.STRING) ? cell.getStringCellValue()
: (cell.getCellType() == CellType.NUMERIC) ? "" + cell.getNumericCellValue()
: (cell.getCellType() == CellType.BOOLEAN) ? "" + cell.getBooleanCellValue()
: (cell.getCellType() == CellType.BLANK) ? ""
: (cell.getCellType() == CellType.FORMULA) ? "FORMULA"
: (cell.getCellType() == CellType.ERROR) ? "ERROR" : "";
cellNew = hssfRowNew.createCell(cell.getColumnIndex(), CellType.STRING);
cellNew.setCellValue(cellValue);
}
}
// NOTICE how I write to the new workbook
hssfWorkbookNew.write(excelNewOutputStream);
hssfWorkbook.close();
hssfWorkbookNew.close();
excelNewOutputStream.close();
JOptionPane.showMessageDialog(null, Constantes.MSG_EXITO, "Informacion", 1);
} catch (FileNotFoundException fileNotFoundException) {
JOptionPane.showMessageDialog(null, "file not found", "Error", 0);
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "Error processing the file", "Error", 0);
} finally {
try {
excelStream.close();
} catch (IOException ex) {
System.out.println("Error processing the file after closing it): " + ex);
}
}
}
I had to handle XSSF and HSSF; this is how it was accomplished:
void handle(File inFile, File outFile) throws IOException {
Workbook workbook = WorkbookFactory.create(inFile);
workbook.setMissingCellPolicy(MissingCellPolicy.RETURN_BLANK_AS_NULL); // LINE NOT REQUIRED
if (workbook instanceof XSSFWorkbook) {
handleXSSF((XSSFWorkbook) workbook, outFile);
} else if (workbook instanceof HSSFWorkbook) {
handleHSSF((HSSFWorkbook) workbook, outFile);
} else {
throw new IOException("Unrecognized Workbook Type " + workbook.getClass().getName());
}
}
void handleHSSF(HSSFWorkbook hWorkbook, File outFile) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
hWorkbook.write(fos);
fos.close();
} finally {
try {
hWorkbook.close();
} catch (Exception ignore) {}
}
}
void handleXSSF(XSSFWorkbook xWorkbook, File outFile) throws IOException {
SXSSFWorkbook sWorkbook = new SXSSFWorkbook(xWorkbook, 100);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
sWorkbook.write(fos);
fos.close();
} finally {
try {
sWorkbook.close();
} catch (Exception ignore) {}
try {
sWorkbook.dispose();
} catch (Exception ignore) {}
try {
xWorkbook.close();
} catch (Exception ignore) {}
}
}
Perhaps you could also just use the create signature
Workbook workbook = WorkbookFactory.create(new File("//server/path/file.ext"), null, true);
to ask POI to open the spreadsheet read only?
Related
I am writing to an existing excel file using Java, say this is fileA. (I'm using APACHE POI for this.)
It is possible that the excel fileA is opened by someone. It is saved in a shared folder accessed by a lot of people.
I want to avoid encountering
java.io.FileNotFoundException: (The process cannot access the file
because it is being used by another process)
Because no matter if the existing excel file is opened or not, I need to save the output of my Java app.
Upon researching, I think it is impossible to close fileA (opened by some other process/user, not by my Java App) within my Java code.
What I'm doing now is to create a new excel file, say fileB if fileA is currently opened. I'm using the code below.
File file = null;
FileOutputStream out = null;
int workbookNo = 0;
do{
String append = "";
if(workbookNo != 0){
append = "_Copy" + Integer.toString(workbookNo);
}
file = new File(filePath + "ValidateLock_" + dataDate + append + ".xlsx");
try{
out = new FileOutputStream(file);
workbookNo = 0;
}catch(FileNotFoundException e){
//e.printStackTrace();
workbookNo++;
}
}while(workbookNo != 0);
However, I'm getting the error below.
org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException: No
valid entries or contents found, this is not a valid OOXML (Office
Open XML) file
try like this :
try {
FileInputStream file = new FileInputStream(new File("C:\\update.xls"));
HSSFWorkbook workbook = new HSSFWorkbook(file);
HSSFSheet sheet = workbook.getSheetAt(0);
Cell cell = null;
//Update the value of cell
cell = sheet.getRow(1).getCell(2);
cell.setCellValue(cell.getNumericCellValue() * 2);
cell = sheet.getRow(2).getCell(2);
cell.setCellValue(cell.getNumericCellValue() * 2);
cell = sheet.getRow(3).getCell(2);
cell.setCellValue(cell.getNumericCellValue() * 2);
//Close the excel input file (inputstream)
file.close();
FileOutputStream outFile =new FileOutputStream(new File("C:\\update.xls"));
workbook.write(outFile);
//Close output excel file
outFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
This is what I need to do.
1) Accept an xlsx/xls file from client.
2) Backend will receive it in the form of multipart file
3) The file will be processed and if the format of the data is invalid, that same file will be updated and the error message will be written in the side of the input of the client.
4) this modified file will be sent back to the user.
But after several attempts, I could not make my code work.
def generateErrorReport(ServletResponse response, Map messageCollections, MultipartFile file, String ext){
FileInputStream fileIn = file.getInputStream()
Workbook workbook = (ext.equalsIgnoreCase("xls")) ? new HSSFWorkbook(fileIn) : new XSSFWorkbook(fileIn)
workbook = this.getWorkbook((MultipartFile) file, ext.equalsIgnoreCase("xls"));
try {
Sheet sheet = workbook.getSheetAt(0)
Long lastCellNum = sheet.getRow(0).getLastCellNum();
for(int i=1; i<sheet.getLastRowNum(); i++){
if(messageCollections[i]!=null && messageCollections[i]!=[] ) {
Cell cell = sheet.getRow(i).getCell(lastCellNum + 1)
cell.setCellValue(messageCollections[i]);
}
}
fileIn.close()
FileOutputStream fileOut = new FileOutputStream((File) file)
workbook.write(fileOut);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response.setHeader("Content-Disposition", "Attachment;Filename=error.xlsx")
response.outputStream << fileOut
response.outputStream.flush()
fileOut.close()
}catch(Exception ex){
println ex
}
}
Now, I think a found way to do it, that is to use POITransformer. The problem is it is used when you have a template. My idea was to use the file sent by the client as template and then just simply write the error message beside the client's input. However I couldnt find a way to write it because I couldn't find a setCellData or any method same as that.
The question is, is it possible to write to a desired cell data using POITransformer? If yes, how will I do that?
So far this is what i've done. But it still not writing. Could you tell me whats wrong?
private void bla(ServletResponse response, Map messageCollections, MultipartFile file, String ext){
InputStream is = file.getInputStream();
OutputStream os = response.outputStream;
String fileName = "error";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "Attachment;Filename=${fileName}");
try {
PoiTransformer transformer = PoiTransformer.createTransformer(is, os);
org.apache.poi.ss.usermodel.Workbook workbook = transformer.getWorkbook()
Sheet sheet = workbook.getSheetAt(workbook.getActiveSheetIndex())
int lastColNum = sheet.getRow(0).getLastCellNum()
Cell cellData;
(0..sheet.getLastRowNum()) {
if (messageCollections[it]!=null && messageCollections[it]!=[]) {
cellData = sheet.getRow(it).getCell(lastColNum+1);
cellData.setCellValue(messageCollections[it].toString())
}
}
transformer.write();
} catch (IOException ex) {
println ex
// Logger.getLogger(ExcelFileHandler.class.getName()).log(Level.SEVERE, null, ex);
} finally {
closeStream(is);
closeStream(os);
}
}
Hopefully, this answer would be helpful to others.
InputStream is = file.getInputStream();
OutputStream os = response.outputStream;
String fileName = "desiredFilename." + ext
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "Attachment;Filename=${fileName}");
try {
PoiTransformer transformer = PoiTransformer.createTransformer(is, os);
org.apache.poi.ss.usermodel.Workbook workbook = transformer.getWorkbook()
Sheet sheet = workbook.getSheetAt(workbook.getActiveSheetIndex())
int lastColNum = sheet.getRow(0).getLastCellNum()
Cell cell;
cell = sheet.getRow(0).getCell(lastColNum);
if(cell==null){
cell = sheet.getRow(0).createCell(lastColNum);
}
cell.setCellType(1)
cell.setCellValue("Message")
cell.setCellStyle(getStyle(workbook, 2))
for(int it=1; it<sheet.getLastRowNum(); it++) {
if (message.get(new Long(it))!=null && message.get(new Long(it))!=[]) {
cell = sheet.getRow(it).getCell(lastColNum);
if(cell==null){
cell = sheet.getRow(it).createCell(lastColNum);
}
cell.setCellType(1)
cell.setCellValue(message.get(new Long(it)).join(', '))
cell.setCellStyle(getStyle(workbook, 1))
}
}
sheet.autoSizeColumn(lastColNum);
transformer.write();
I am trying to check if my excel file already exists. If it doesn't exists, I want to create a new one and if it exists I will delete it and create a new one. I wrote following program but I am getting error at line - workbook= WorkbookFactory.create(instream);
The error is->
java.lang.IllegalArgumentException: Your InputStream was neither an OLE2 stream, nor an OOXML stream
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:89)
at tryIng.main(tryIng.java:84)
Here is a program ->
try {
String filePath= "C:/Users/pritik/Desktop/t1.xlsx";
File file = new File(filePath);
filePath= file.getAbsolutePath();
xlFile = new File(filePath);
if(xlFile.exists() && !xlFile.isDirectory())
xlFile.delete(); //delete if file already exists.
xlFile.createNewFile();
inStream = new FileInputStream(xlFile);
workbook = WorkbookFactory.create(inStream); // I get error at this line
String sheetName="NewSheet";
Sheet sheet = workbook.createSheet(sheetName);
FileOutputStream fOut = new FileOutputStream(xlFile);
int i,j;
xRows = xTS.length;
xCols = xTS[0].length;
for(i =0;i<xRows;i++)
{
row = sheet.createRow(i);
for(j=0;j<xCols;j++)
{
cell = row.createCell(j);
cell.setCellType(Cell.CELL_TYPE_STRING);
cell.setCellValue(xTS[i][j]);
}
}
workbook.write(fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Don't create an empty file and try to read it, that won't work. An empty zero byte file is not valid, and can't be loaded Instead, have POI create an new file for you, which you will write later.
Change the code:
if(xlFile.exists() && !xlFile.isDirectory())
xlFile.delete(); //delete if file already exists.
xlFile.createNewFile();
inStream = new FileInputStream(xlFile);
workbook = WorkbookFactory.create(inStream);
To instead be:
if(xlFile.exists() && !xlFile.isDirectory())
xlFile.delete(); //delete if file already exists.
if (xlFile.toString().endsWith(".xls") {
workbook = new HSSFWorkbook();
} else {
workbook = new XSSFWorkbook();
}
Also, if you do want to read an existing file, don't use a stream if you have a file! See this bit of the POI docs for why not.
This is my class to read and write existing excel files. I have been calling these functions in the main class by passing the filePath and fileName.
public class NewExcelFile {
Workbook workbook;
/******* Methods *******/
// returns a workbook on giving the excel file's path and name
public Workbook readExcel(String filePath, String fileName) {
// Create object of File class to open xlsx file
File file = new File(filePath + "\\" + fileName);
// Create an object of FileInputStream class to read excel file
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
System.out.println("Error: Unable to find " + fileName + " in "
+ filePath);
e.printStackTrace();
}
Workbook workbook = null;
// Find the file extension by spliting file name in substring and
// getting only extension name
String fileExtensionName = fileName.substring(fileName.indexOf("."));
// Check condition if the file is xlsx file
if (fileExtensionName.equals(".xlsx")) {
// If it is xlsx file then create object of XSSFWorkbook class
try {
workbook = new XSSFWorkbook(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// Check condition if the file is xls file
else if (fileExtensionName.equals(".xls")) {
// If it is xls file then create object of XSSFWorkbook class
try {
workbook = new HSSFWorkbook(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
this.workbook = workbook;
return workbook;
}
public void writeExcel(String filePath, String fileName, String sheetName,
String dataToWrite, int rowno) {
System.out.println("WriteExcel" + filePath + " " + fileName + " "
+ sheetName + " " + dataToWrite + " " + rowno);
Workbook newWorkbook = readExcel(filePath, fileName);
Sheet sheet = newWorkbook.getSheet(sheetName);
System.out.println("Sheet: " + sheet.getSheetName());
Cell resultcell;
******resultcell = sheet.getRow(rowno).createCell(8);
resultcell.setCellType(Cell.CELL_TYPE_STRING);
resultcell.setCellValue(dataToWrite);
CellStyle style = workbook.createCellStyle();
if (dataToWrite == "P") {
style.setFillBackgroundColor(IndexedColors.GREEN.getIndex());
style.setFillPattern(CellStyle.ALIGN_FILL);
resultcell.setCellStyle(style);
} else if (dataToWrite == "F") {
style.setFillBackgroundColor(IndexedColors.RED.getIndex());
style.setFillPattern(CellStyle.ALIGN_FILL);
resultcell.setCellStyle(style);
}
// Create an object of FileOutputStream class to create write data in
// excel file
File file = new File(filePath + "\\" + fileName);
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
System.out.println("File not found");
e.printStackTrace();
}
// write data in the excel file and close output stream
try {
workbook.write(outputStream);
outputStream.close();
} catch (IOException e) {
System.out.println("Error in writing to file");
e.printStackTrace();
}
}
When I get a workbook in the main using readExcel and call this function:
Row row = testScriptsSheet.getRow(24);
I get the correct row and am able to call all functions on this row.But for the exact same row in the exact same sheet in the writeExcel(), I get a null pointer exception(the line preceded by *** in the code above). getRow() gives me null here. What am I doing wrong here?
Also, should I keep workbook as a data member and domyNewExcelFile.workbook whenever I need it or keep it as a variable returned from the readExcel in the main class?
Also I was wondering what is happening now that I am not closing the inputStream at the end of the readExcel function. I get the same error whether I close the inputStream or not.
EDIT - Adding the main function
public class NewDriver {
public static void main(String[] args) {
System.out.println("Starting the framework");
// initialise the workbook
NewExcelFile testExecution = new NewExcelFile();
testExecution.readExcel(System.getProperty("user.dir") + "\\",
"abc.xlsx");
// initialise sheets of workbook
Sheet testSuiteSheet = testExecution.workbook.getSheet("TestSuite");
Sheet testScriptsSheet = testExecution.workbook.getSheet("TestCases");
Row row = testScriptsSheet.getRow(24);//gives the correct row
//calling writeExcel gives npe in that line
}
}
}
}
From the docs the getRow(int) method:
Returns the logical row (not physical) 0-based. If you ask for a row
that is not defined you get a null. This is to say row 4 represents
the fifth row on a sheet.
So when a row is not defined, you must first create the row and then create the cell.
As per my understanding it seems a conceptual error. Before calling WriteExcel() method, all the changes that you have made in main method are in buffer, not written in the excel sheet/workbook present in your harddisk. But in WriteExcel() method you are not passing the sheet or workbook you kept in buffer, but the address of the one physically present in the hard drive. So any change you have done in main function is not there, hence showing null pointer exception.
e.g. I have one workbook in say my D Drive, having value 1 in A0. Now I have programmatically made it 2 but not perform the write operation, and put the execution on hold. Meanwhile I went to my D drive and open the sheet there will be 1 not 2, as the updated value is in buffer, till I have perform write operation on that workbook.
Suggestion: Instead of passing the address of the workbook, why not you just pass the workbook you have used in main method.
UPDATE: Not the main method but readExcel(String filePath, String fileName) method actually.
I want to have just a single FileOutputStream that writes contents of my workbook to a file in my application, and create multiple worksheets within this excel. I am using Apache POI to read/write to my excel. I have the below method where I am doing this -
private static void writeToSpreadSheet(String test,Map<String,String> errorMap,Object object) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook()
HSSFSheet sheet = workbook.createSheet(test);
FileOutputStream fis = new FileOutputStream("output/test.xls");
//do stuff and finally write workbook contents to a file
workbook.write(fis);
if (fis != null)
fis.close();
}
The problem I am facing here is, every time I called the writeToSpreadSheet, a new file is getting created, and the existing data is getting overwritten. I want one file only, and
need new worksheeets to be added to my existing file. How do I achieve this?
I am not near my machine so I can't provide you the exact code base, but if you follow the exact steps then you could achieve the desired results.
I have assembled the code from here and there and its not going to work as is. You have to modify the code and made it work the way you wanted. I leave that part for you.
final File file = "/output/test.xls";
HSSFWorkbook workbook = null;
FileOutputStream fileOut = new FileOutputStream(file);
private static void writeToSpreadSheet(String test,
Map<String, String> errorMap, Object object) throws IOException {
// Check whether your file exist
// if not then crate a workbook
// something like below
if (!file.exists()) {
System.out.println("Creating a new workbook '" + file + "'");
workbook = new HSSFWorkbook();
} else {
// create a method to get very last sheet number something like
// following .
int sheetIndex = getLastSheetIndex();
// if you dont to go with find last sheet index idea then you can
// create your unique name may be like timestamp or so
// add the new sheet with new index
HSSFSheet sheet = workbook.createSheet("Test Sheet " + sheetIndex);
// Write your content
workbook.write(fileOut);
fileOut.close();
}
}
private static int getLastSheetIndex() {
int sheetIndex = 1;
while (workbook.getSheet("Test Sheet " + sheetIndex) != null) {
sheetIndex++;
}
return sheetIndex;
}
Currently what are you doing:
private static void writeToSpreadSheet(String test,
Map<String, String> errorMap, Object object) throws IOException {
// Creating the new workbook every time you call this method
HSSFWorkbook workbook = new HSSFWorkbook();
// Adding the same sheet to newly created workbook
HSSFSheet sheet = workbook.createSheet(test);
FileOutputStream fis = new FileOutputStream("output/test.xls");
// causing to overwrite your old workbook
workbook.write(fis);
if (fis != null)
fis.close();
}