I am trying to generate excel file using the following approach:
private static final String CONTENT_TYPE = "multipart/form-data";
private static final String FILE_NAME = "DemoReport";
private static final String FILE_EXTENSION = ".xlsx";
public MultipartFile export(final UUID uuid) throws IOException {
final XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Report");
int rowCount = 0;
final List<ProductDTO> productList = productService
.findAllByCategory(categoryUuid);
writeTitles(sheet.createRow(rowCount++), titles); // private method
// code omitted
final File outputFile = File.createTempFile(FILE_NAME, FILE_EXTENSION);
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
workbook.write(outputStream);
} catch (IOException e) {
LoggingUtils.error("error... ", e);
}
final FileInputStream input = new FileInputStream(outputFile);
final String fileName = FILE_NAME.concat(FILE_EXTENSION);
return new MockMultipartFile(fileName,
fileName, CONTENT_TYPE, IOUtils.toByteArray(input));
}
However, the generated file has no extension (its type is File). So, what is the problem that causes this and how to fix?
I want to write the output of the displayDirectoryContents to a excel sheet
I have tried using the Apache POI method I want to get the output to a excel sheet
Folder and filename in one column and
the name of the files in another column
import statements
public class Excel {
private static String dest = "C:\\Users\\mahselva\\testexcel.xls";
private static HSSFWorkbook myWorkBook = new HSSFWorkbook();
private static HSSFSheet mySheet = myWorkBook.createSheet();
public static void excelLog(String filename, String message, int rowNum)
{
HSSFRow myRow = null;
HSSFCell myCell = null;
String excelData[][] = new String[1][2];
excelData[0][0] = filename;
excelData[0][1] = message;
myRow = mySheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 2; cellNum++) {
myCell = myRow.createCell(cellNum);
myCell.setCellValue(excelData[0][cellNum]);
}
try {
FileOutputStream out = new FileOutputStream(dest);
myWorkBook.write(out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
File currentDir = new File("C:\\OracleATS\\openScript"); // current
directory
displayDirectoryContents(currentDir);
}
public static void displayDirectoryContents(File dir) {
try {
int i = 0;
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
Path path = Paths.get(file.getCanonicalPath());
//System.out.println("Folder"
+path.getFileName().toString());
excelLog("Folder",path.getFileName().toString(),i);
i++;
displayDirectoryContents(file);
} else {
Path path = Paths.get(file.getCanonicalPath());
//System.out.println(path.getFileName().toString());
excelLog("File",path.getFileName().toString(),i);
i++;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I want two columns in an excel sheet with column 1 containing File or
Folder and column 2 containing the name of the file/folder
eg
File books.xml
Folder Script
Thus i want to write the output to the excel sheet
i am using the function excel log to write to the output screen
I use this to write to an excel - however I make it .csv format, not xls. Therefore this might not be what you need, but it's still partially useful as it's writing in a file that can be opened by excel efortlessly.
public static void printAtFile(String filename, String header, String content[])
{
filename+=".csv";
System.out.println("Start creating file "+filename);
PrintWriter writer = null;
try {
writer = new PrintWriter(filename);
writer.println(header);
for(String u:content)
writer.println(u);
writer.close();
} catch (Exception ex) {
System.out.println("Error while writing at file "+filename);
}
}
I would like to insert values into existing work book. Here the class that encapsulates this logic:
public class FormulaExtractor {
private String pathToExcelFile;
private XSSFWorkbook workbook;
private Map<Double, Formula> idFormular = new HashMap<>();
public FormulaExtractor(String pathToExcelFile) {
this.pathToExcelFile = pathToExcelFile;
try (FileInputStream fileInputStream = new FileInputStream(new File(pathToExcelFile))) {
this.workbook = new XSSFWorkbook(fileInputStream);
} catch (FileNotFoundException e) {
System.out.println("Cannot locate a xls file. Exception: " + e.toString());
} catch (IOException e) {
System.out.println("IO exception " + e.toString());
}
}
public void insertHumanReadableFormulas() throws IOException {
XSSFSheet sheet = workbook.getSheetAt(0);
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row currentRow = rowIterator.next();
Cell cell = currentRow.createCell(CellReference.convertColStringToIndex("K"));
cell.setCellValue("Some dummy variable to test. ");
}
FileOutputStream fileOut = new FileOutputStream(new File(this.pathToExcelFile));
workbook.write(fileOut);
fileOut.close();
}
}
How do I use it:
public class App {
public static void main(String[] args) throws IOException {
final String pathToExcel = "some/path/some_excel.xlsx";
FormulaExtractor formulaExtractor = new FormulaExtractor(pathToExcel);
formulaExtractor.insertHumanReadableFormulas();
}
}
I don't get any exception or error. When I open my excel file, I simply cannot find values in a column "K". What am I doing wrong?
I am trying to read large excel files xlsx via Apache POI, say 40-50 MB. I am getting out of memory exception. The current heap memory is 3GB.
I can read smaller excel files without any issues. I need a way to read large excel files and then them back as response via Spring excel view.
public class FetchExcel extends AbstractView {
#Override
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String fileName = "SomeExcel.xlsx";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
OPCPackage pkg = OPCPackage.open("/someDir/SomeExcel.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(pkg);
ServletOutputStream respOut = response.getOutputStream();
pkg.close();
workbook.write(respOut);
respOut.flush();
workbook = null;
response.setHeader("Content-disposition", "attachment;filename=\"" +fileName+ "\"");
}
}
I first started off using XSSFWorkbook workbook = new XSSFWorkbook(FileInputStream in);
but that was costly per Apache POI API, so I switched to OPC package way but still the same effect. I don't need to parse or process the file, just read it and return it.
Here is an example to read a large xls file using sax parser.
public void parseExcel(File file) throws IOException {
OPCPackage container;
try {
container = OPCPackage.open(file.getAbsolutePath());
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(container);
XSSFReader xssfReader = new XSSFReader(container);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
while (iter.hasNext()) {
InputStream stream = iter.next();
processSheet(styles, strings, stream);
stream.close();
}
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (OpenXML4JException e) {
e.printStackTrace();
}
}
protected void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream) throws IOException, SAXException {
InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
ContentHandler handler = new XSSFSheetXMLHandler(styles, strings, new SheetContentsHandler() {
#Override
public void startRow(int rowNum) {
}
#Override
public void endRow() {
}
#Override
public void cell(String cellReference, String formattedValue) {
}
#Override
public void headerFooter(String text, boolean isHeader, String tagName) {
}
},
false//means result instead of formula
);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
} catch (ParserConfigurationException e) {
throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
}
You don't mention whether you need to modify the spreadsheet or not.
This may be obvious, but if you don't need to modify the spreadsheet, then you don't need to parse it and write it back out, you can simply read bytes from the file, and write out bytes, as you would with, say an image, or any other binary format.
If you do need to modify the spreadsheet before sending it to the user, then to my knowledge, you may have to take a different approach.
Every library that I'm aware of for reading Excel files in Java reads the whole spreadsheet into memory, so you'd have to have 50MB of memory available for every spreadsheet that could possibly be concurrently processed. This involves, as others have pointed out, adjusting the heap available to the VM.
If you need to process a large number of spreadsheets concurrently, and can't allocate enough memory, consider using a format that can be streamed, instead of read all at once into memory. CSV format can be opened by Excel, and I've had good results in the past by setting the content-type to application/vnd.ms-excel, setting the attachment filename to something ending in ".xls", but actually returning CSV content. I haven't tried this in a couple of years, so YMMV.
In the bellwo example I'll add a complete code how to parse a complete excel file (for me 60Mo) into list of object without any problem of "out of memory" and work fine:
import java.util.ArrayList;
import java.util.List;
class DistinctByProperty {
private static OPCPackage xlsxPackage = null;
private static PrintStream output= System.out;
private static List<MassUpdateMonitoringRow> resultMapping = new ArrayList<>();
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\aberguig032018\\Downloads\\your_excel.xlsx");
double bytes = file.length();
double kilobytes = (bytes / 1024);
double megabytes = (kilobytes / 1024);
System.out.println("Size "+megabytes);
parseExcel(file);
}
public static void parseExcel(File file) throws IOException {
try {
xlsxPackage = OPCPackage.open(file.getAbsolutePath(), PackageAccess.READ);
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(xlsxPackage);
XSSFReader xssfReader = new XSSFReader(xlsxPackage);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
int index = 0;
while (iter.hasNext()) {
try (InputStream stream = iter.next()) {
String sheetName = iter.getSheetName();
output.println();
output.println(sheetName + " [index=" + index + "]:");
processSheet(styles, strings, new MappingFromXml(resultMapping), stream);
}
++index;
}
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (OpenXML4JException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
private static void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, MappingFromXml mappingFromXml, InputStream sheetInputStream) throws IOException, SAXException {
DataFormatter formatter = new DataFormatter();
InputSource sheetSource = new InputSource(sheetInputStream);
try {
XMLReader sheetParser = SAXHelper.newXMLReader();
ContentHandler handler = new XSSFSheetXMLHandler(
styles, null, strings, mappingFromXml, formatter, false);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
System.out.println("Size of Array "+resultMapping.size());
} catch(ParserConfigurationException e) {
throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
}
}
}
you have to add a calss that implements
SheetContentsHandler
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class MappingFromXml implements SheetContentsHandler {
private List<myObject> result = new ArrayList<>();
private myObject myObject = null;
private int lineNumber = 0;
/**
* Number of columns to read starting with leftmost
*/
private int minColumns = 25;
/**
* Destination for data
*/
private PrintStream output = System.out;
public MappingFromXml(List<myObject> list) {
this.result = list;
}
#Override
public void startRow(int i) {
output.println("iii " + i);
lineNumber = i;
myObject = new myObject();
}
#Override
public void endRow(int i) {
output.println("jjj " + i);
result.add(myObject);
myObject = null;
}
#Override
public void cell(String cellReference, String formattedValue, XSSFComment comment) {
int columnIndex = (new CellReference(cellReference)).getCol();
if(lineNumber > 0){
switch (columnIndex) {
case 0: {//Tech id
if (formattedValue != null && !formattedValue.isEmpty())
myObject.setId(Integer.parseInt(formattedValue));
}
break;
//TODO add other cell
}
}
}
#Override
public void headerFooter(String s, boolean b, String s1) {
}
}
For more information visite this link
I too faced the same issue of OOM while parsing xlsx file...after two days of struggle, I finally found out the below code that was really perfect;
This code is based on sjxlsx. It reads the xlsx and stores in a HSSF sheet.
[code=java]
// read the xlsx file
SimpleXLSXWorkbook = new SimpleXLSXWorkbook(new File("C:/test.xlsx"));
HSSFWorkbook hsfWorkbook = new HSSFWorkbook();
org.apache.poi.ss.usermodel.Sheet hsfSheet = hsfWorkbook.createSheet();
Sheet sheetToRead = workbook.getSheet(0, false);
SheetRowReader reader = sheetToRead.newReader();
Cell[] row;
int rowPos = 0;
while ((row = reader.readRow()) != null) {
org.apache.poi.ss.usermodel.Row hfsRow = hsfSheet.createRow(rowPos);
int cellPos = 0;
for (Cell cell : row) {
if(cell != null){
org.apache.poi.ss.usermodel.Cell hfsCell = hfsRow.createCell(cellPos);
hfsCell.setCellType(org.apache.poi.ss.usermodel.Cell.CELL_TYPE_STRING);
hfsCell.setCellValue(cell.getValue());
}
cellPos++;
}
rowPos++;
}
return hsfSheet;[/code]
I have excel. and I create macro to the excel file to read data from other resources. the macro run every second and update its excel cells.
Now, I want to build java program to read the excel data every seconds to. I have try Apache POI, but after I check the documentation ti doesn't support reading excel file with macro.
I read from some resources Java Com Bridge (JCOB) can be used to read excel with macro. I've try, But the cell value still not updated every times I try my code.
import com.jacob.com.*;
import com.jacob.activeX.*;
public class ExcelTest {
private static ActiveXComponent xl;
private static Dispatch workbooks = null;
private static Dispatch workbook = null;
private static Dispatch sheet = null;
private static String filename = null;
private static boolean readonly = false;
public static void main(String[] args) {
String file = "D:\\tutorial\\ApachePoi\\ratesource.xls";
OpenExcel(file, false); // do not show false to open Excel
System.out.println(GetValue("B46"));
}
private static void OpenExcel(String file, boolean f) {
try {
filename = file;
xl = new ActiveXComponent("Excel.Application");
xl.setProperty("Visible", new Variant(f));
workbooks = xl.getProperty("Workbooks").toDispatch();
workbook = Dispatch.invoke(
workbooks,
"Open",
Dispatch.Method,
new Object[] { filename, new Variant(false),
new Variant(readonly) },// whether to open read-only
new int[1]).toDispatch();
} catch (Exception e) {
e.printStackTrace();
}
}
// Read value
private static String GetValue(String position) {
if (workbook == null) {
System.out.println("workbook is null");
}
sheet = Dispatch.get(workbook, "ActiveSheet").toDispatch();
Object cell = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[]{position}, new int[1]).toDispatch();
String value = Dispatch.get((Dispatch) cell, "Value").toString();
return value;
}
//1.3638356164383563
//1.3638356164383563
private static void SetValue (String position, String type, String value)
{
}
}
I am unfamiliar with an Excel engine capable of doing what you describe.
Have you considered talking to Excel instead and ask it for its values when running your spread-sheet? I believe you can do so with ODBC.
Another approach might be creating an OpenOffice version of your sheet and talk to OpenOffice instead.
One pitfall is poi don't change the value of the existing excel write to another file and you can see the difference
workbook.getSheet().getRow(1).getCell(0).setValue("test");
and write this(changed) workbook to another file
public void writeFile(String fileName) {
FileOutputStream fos;
try {
fos = new FileOutputStream(fileName);
getWorkbook().write(fos);
fos.close();
} catch (IOException e) {
System.out.println("IOException occurs");
e.printStackTrace();
}
}