Reading an Excel sheet using POI's XSSF and SAX (Event API) - java

I am reading an Excel sheet using POI's XSSF and SAX (Event API). The Excel sheet has thousands of rows of user information like user name, email, address, age, department etc.
I need to read each row from Excel, convert it into a User object and add this User object to a List of User objects.
I can read the Excel sheet successfully, but I am not sure at what point while reading I should create an instance of the User object and populate it with the data from the Excel sheet.
Below is my entire working code.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class ExcelSheetParser {
enum xssfDataType {
BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER,
}
int countrows = 0;
class XSSFSheetHandler extends DefaultHandler {
/**
* Table with styles
*/
private StylesTable stylesTable;
/**
* Table with unique strings
*/
private ReadOnlySharedStringsTable sharedStringsTable;
/**
* Destination for data
*/
private final PrintStream output;
private List<?> list = new ArrayList();
private Class clazz;
/**
* Number of columns to read starting with leftmost
*/
private final int minColumnCount;
// Set when V start element is seen
private boolean vIsOpen;
// Set when cell start element is seen;
// used when cell close element is seen.
private xssfDataType nextDataType;
// Used to format numeric cell values.
private short formatIndex;
private String formatString;
private final DataFormatter formatter;
private int thisColumn = -1;
// The last column printed to the output stream
private int lastColumnNumber = -1;
// Gathers characters as they are seen.
private StringBuffer value;
/**
* Accepts objects needed while parsing.
*
* #param styles
* Table of styles
* #param strings
* Table of shared strings
* #param cols
* Minimum number of columns to show
* #param target
* Sink for output
*/
public XSSFSheetHandler(StylesTable styles,
ReadOnlySharedStringsTable strings, int cols, PrintStream target, Class clazz) {
this.stylesTable = styles;
this.sharedStringsTable = strings;
this.minColumnCount = cols;
this.output = target;
this.value = new StringBuffer();
this.nextDataType = xssfDataType.NUMBER;
this.formatter = new DataFormatter();
this.clazz = clazz;
}
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if ("inlineStr".equals(name) || "v".equals(name)) {
vIsOpen = true;
// Clear contents cache
value.setLength(0);
}
// c => cell
else if ("c".equals(name)) {
// Get the cell reference
String r = attributes.getValue("r");
int firstDigit = -1;
for (int c = 0; c < r.length(); ++c) {
if (Character.isDigit(r.charAt(c))) {
firstDigit = c;
break;
}
}
thisColumn = nameToColumn(r.substring(0, firstDigit));
// Set up defaults.
this.nextDataType = xssfDataType.NUMBER;
this.formatIndex = -1;
this.formatString = null;
String cellType = attributes.getValue("t");
String cellStyleStr = attributes.getValue("s");
if ("b".equals(cellType))
nextDataType = xssfDataType.BOOL;
else if ("e".equals(cellType))
nextDataType = xssfDataType.ERROR;
else if ("inlineStr".equals(cellType))
nextDataType = xssfDataType.INLINESTR;
else if ("s".equals(cellType))
nextDataType = xssfDataType.SSTINDEX;
else if ("str".equals(cellType))
nextDataType = xssfDataType.FORMULA;
else if (cellStyleStr != null) {
// It's a number, but almost certainly one
// with a special style or format
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
this.formatIndex = style.getDataFormat();
this.formatString = style.getDataFormatString();
if (this.formatString == null)
this.formatString = BuiltinFormats
.getBuiltinFormat(this.formatIndex);
}
}
}
public void endElement(String uri, String localName, String name)
throws SAXException {
String thisStr = null;
// v => contents of a cell
if ("v".equals(name)) {
// Process the value contents as required.
// Do now, as characters() may be called more than once
switch (nextDataType) {
case BOOL:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "\"ERROR:" + value.toString() + '"';
break;
case FORMULA:
// A formula could result in a string value,
// so always add double-quote characters.
thisStr = '"' + value.toString() + '"';
break;
case INLINESTR:
// TODO: have seen an example of this, so it's untested.
XSSFRichTextString rtsi = new XSSFRichTextString(value
.toString());
thisStr = '"' + rtsi.toString() + '"';
break;
case SSTINDEX:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss = new XSSFRichTextString(
sharedStringsTable.getEntryAt(idx));
thisStr = '"' + rtss.toString() + '"';
} catch (NumberFormatException ex) {
output.println("Failed to parse SST index '" + sstIndex
+ "': " + ex.toString());
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null)
thisStr = formatter.formatRawCellContents(Double
.parseDouble(n), this.formatIndex,
this.formatString);
else
thisStr = n;
break;
default:
thisStr = "(TODO: Unexpected type: " + nextDataType + ")";
break;
}
// Output after we've seen the string contents
// Emit commas for any fields that were missing on this row
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
for (int i = lastColumnNumber; i < thisColumn; ++i)
output.print(',');
// Might be the empty string.
output.print(thisColumn +" : "+thisStr);
// Update column
if (thisColumn > -1)
lastColumnNumber = thisColumn;
} else if ("row".equals(name)) {
// Print out any missing commas if needed
if (minColumns > 0) {
// Columns are 0 based
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
for (int i = lastColumnNumber; i < (this.minColumnCount); i++) {
output.print(',');
}
}
// We're onto a new row
output.println();
output.println(countrows++);
lastColumnNumber = -1;
}
}
/**
* Captures characters only if a suitable element is open. Originally
* was just "v"; extended for inlineStr also.
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
if (vIsOpen)
value.append(ch, start, length);
}
/**
* Converts an Excel column name like "C" to a zero-based index.
*
* #param name
* #return Index corresponding to the specified name
*/
private int nameToColumn(String name) {
int column = -1;
for (int i = 0; i < name.length(); ++i) {
int c = name.charAt(i);
column = (column + 1) * 26 + c - 'A';
}
return column;
}
}
// /////////////////////////////////////
private OPCPackage xlsxPackage;
private int minColumns;
private PrintStream output;
private Class clazz;
/**
* Creates a new XLSX -> CSV converter
*
* #param pkg
* The XLSX package to process
* #param output
* The PrintStream to output the CSV to
* #param minColumns
* The minimum number of columns to output, or -1 for no minimum
*/
public ExcelSheetParser(OPCPackage pkg, PrintStream output, int minColumns, Class clazz) {
this.xlsxPackage = pkg;
this.output = output;
this.minColumns = minColumns;
this.clazz = clazz;
}
/**
* Parses and shows the content of one sheet using the specified styles and
* shared-strings tables.
*
* #param styles
* #param strings
* #param sheetInputStream
*/
public void processSheet(StylesTable styles,
ReadOnlySharedStringsTable strings, InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {
InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
ContentHandler handler = new XSSFSheetHandler(styles, strings,
this.minColumns, this.output, this.clazz);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
}
/**
* Initiates the processing of the XLS workbook file to CSV.
*
* #throws IOException
* #throws OpenXML4JException
* #throws ParserConfigurationException
* #throws SAXException
*/
public void process() throws IOException, OpenXML4JException,
ParserConfigurationException, SAXException {
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(
this.xlsxPackage);
XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader
.getSheetsData();
int index = 0;
while (iter.hasNext()) {
InputStream stream = iter.next();
String sheetName = iter.getSheetName();
this.output.println(sheetName + " [index=" + index + "]:");
processSheet(styles, strings, stream);
stream.close();
++index;
}
}
}

What I'd probably do is start building the User object when the row starts. As you hit the cells in the row, you populate your User object. When the row ends, validate the User object, and if it's fine add it then. Because you're doing SAX parsing, you'll get the start and events for all of these, so you can attach your logic there.
I'd suggest you take a look at XLSX2CSV in the Apache POI Examples. It shows how to go about handling the different kinds of cell contents (which you'll need for populating your user object), how to do something when you reach the end of the row, as well as handling missing cells etc.

I think you can create a user object at following location in your code:
// We're onto a new row
output.println();
// Convert output to a new user object
// ....
// ....

First of all where you are saving value in thisStr variable, if this is a valid value then put this value in Map.
You should create USer object in endElement() method in
else if ("row".equals(name)) {
// use map create USER object here
}
and You can add Users object in global list and if you want to persist it then you can persist it sheet by sheet OR all data at a time.
while (iter.hasNext()) {
InputStream stream = iter.next();
String sheetName = iter.getSheetName();
this.output.println(sheetName + " [index=" + index + "]:");
processSheet(styles, strings, stream);
stream.close();
++index;
//for persisting USERS data sheet by sheet write your code here.........
}
// for persisting complete data of all sheets write your code here...
This is working for me.

Related

converting excel data to JSON format

I am trying to convert excel data into JSON format. but the problem is I have excel sheets which are linked to multiple excel sheet. like example root.xlsx which contains
id, name, phone,department,category,age fields
and where department field refers to department.xlsx which contains
dname, did, dtype
and category fields refers to category.xlsx which contains
catid,catname,cattype,
how to convert it to JSON if the data format is like this?
Jars Required
commons-beanutils-1.8.3.jar
ezmorph-1.0.6.jar
commons-collections-3.2.1.jar
commons-lang-2.6.jar
json-lib-2.4-jdk15.jar
poi
Sample code
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Header;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openqa.selenium.json.Json;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import net.sf.json.JSONObject;
public class ReadExcelDataWithDynamicColumn {
public static void main(String[] args)
{
// You can specify your excel file path.
String excelFilePath = "/Users/zhaosong/Documents/WorkSpace/EmployeeInfo.xls";
// This method will read each sheet data from above excel file and create a JSON and a text file to save the sheet data.
creteJSONAndTextFileFromExcel(excelFilePath);
}
/* Read data from an excel file and output each sheet data to a json file and a text file.
* filePath : The excel file store path.
* */
private static void creteJSONAndTextFileFromExcel(String filePath)
{
try{
/* First need to open the file. */
FileInputStream fInputStream = new FileInputStream(filePath.trim());
/* Create the workbook object to access excel file. */
//Workbook excelWookBook = new XSSFWorkbook(fInputStream)
/* Because this example use .xls excel file format, so it should use HSSFWorkbook class. For .xlsx format excel file use XSSFWorkbook class.*/;
Workbook excelWorkBook = new HSSFWorkbook(fInputStream);
// Get all excel sheet count.
int totalSheetNumber = excelWorkBook.getNumberOfSheets();
// Loop in all excel sheet.
for(int i=0;i<totalSheetNumber;i++)
{
// Get current sheet.
Sheet sheet = excelWorkBook.getSheetAt(i);
// Get sheet name.
String sheetName = sheet.getSheetName();
if(sheetName != null && sheetName.length() > 0)
{
// Get current sheet data in a list table.
List<List<String>> sheetDataTable = getSheetDataList(sheet);
// Generate JSON format of above sheet data and write to a JSON file.
String jsonString = getJSONStringFromList(sheetDataTable);
String jsonFileName = sheet.getSheetName() + ".json";
writeStringToFile(jsonString, jsonFileName);
// Generate text table format of above sheet data and write to a text file.
String textTableString = getTextTableStringFromList(sheetDataTable);
String textTableFileName = sheet.getSheetName() + ".txt";
writeStringToFile(textTableString, textTableFileName);
}
}
// Close excel work book object.
excelWorkBook.close();
}catch(Exception ex){
System.err.println(ex.getMessage());
}
}
/* Return sheet data in a two dimensional list.
* Each element in the outer list is represent a row,
* each element in the inner list represent a column.
* The first row is the column name row.*/
private static List<List<String>> getSheetDataList(Sheet sheet)
{
List<List<String>> ret = new ArrayList<List<String>>();
// Get the first and last sheet row number.
int firstRowNum = sheet.getFirstRowNum();
int lastRowNum = sheet.getLastRowNum();
if(lastRowNum > 0)
{
// Loop in sheet rows.
for(int i=firstRowNum; i<lastRowNum + 1; i++)
{
// Get current row object.
Row row = sheet.getRow(i);
// Get first and last cell number.
int firstCellNum = row.getFirstCellNum();
int lastCellNum = row.getLastCellNum();
// Create a String list to save column data in a row.
List<String> rowDataList = new ArrayList<String>();
// Loop in the row cells.
for(int j = firstCellNum; j < lastCellNum; j++)
{
// Get current cell.
Cell cell = row.getCell(j);
// Get cell type.
int cellType = cell.getCellType();
if(cellType == CellType.NUMERIC.getCode())
{
double numberValue = cell.getNumericCellValue();
// BigDecimal is used to avoid double value is counted use Scientific counting method.
// For example the original double variable value is 12345678, but jdk translated the value to 1.2345678E7.
String stringCellValue = BigDecimal.valueOf(numberValue).toPlainString();
rowDataList.add(stringCellValue);
}else if(cellType == CellType.STRING.getCode())
{
String cellValue = cell.getStringCellValue();
rowDataList.add(cellValue);
}else if(cellType == CellType.BOOLEAN.getCode())
{
boolean numberValue = cell.getBooleanCellValue();
String stringCellValue = String.valueOf(numberValue);
rowDataList.add(stringCellValue);
}else if(cellType == CellType.BLANK.getCode())
{
rowDataList.add("");
}
}
// Add current row data list in the return list.
ret.add(rowDataList);
}
}
return ret;
}
/* Return a JSON string from the string list. */
private static String getJSONStringFromList(List<List<String>> dataTable)
{
String ret = "";
if(dataTable != null)
{
int rowCount = dataTable.size();
if(rowCount > 1)
{
// Create a JSONObject to store table data.
JSONObject tableJsonObject = new JSONObject();
// The first row is the header row, store each column name.
List<String> headerRow = dataTable.get(0);
int columnCount = headerRow.size();
// Loop in the row data list.
for(int i=1; i<rowCount; i++)
{
// Get current row data.
List<String> dataRow = dataTable.get(i);
// Create a JSONObject object to store row data.
JSONObject rowJsonObject = new JSONObject();
for(int j=0;j<columnCount;j++)
{
String columnName = headerRow.get(j);
String columnValue = dataRow.get(j);
rowJsonObject.put(columnName, columnValue);
}
tableJsonObject.put("Row " + i, rowJsonObject);
}
// Return string format data of JSONObject object.
ret = tableJsonObject.toString();
}
}
return ret;
}
/* Return a text table string from the string list. */
private static String getTextTableStringFromList(List<List<String>> dataTable)
{
StringBuffer strBuf = new StringBuffer();
if(dataTable != null)
{
// Get all row count.
int rowCount = dataTable.size();
// Loop in the all rows.
for(int i=0;i<rowCount;i++)
{
// Get each row.
List<String> row = dataTable.get(i);
// Get one row column count.
int columnCount = row.size();
// Loop in the row columns.
for(int j=0;j<columnCount;j++)
{
// Get column value.
String column = row.get(j);
// Append column value and a white space to separate value.
strBuf.append(column);
strBuf.append(" ");
}
// Add a return character at the end of the row.
strBuf.append("\r\n");
}
}
return strBuf.toString();
}
/* Write string data to a file.*/
private static void writeStringToFile(String data, String fileName)
{
try
{
// Get current executing class working directory.
String currentWorkingFolder = System.getProperty("user.dir");
// Get file path separator.
String filePathSeperator = System.getProperty("file.separator");
// Get the output file absolute path.
String filePath = currentWorkingFolder + filePathSeperator + fileName;
// Create File, FileWriter and BufferedWriter object.
File file = new File(filePath);
FileWriter fw = new FileWriter(file);
BufferedWriter buffWriter = new BufferedWriter(fw);
// Write string data to the output file, flush and close the buffered writer object.
buffWriter.write(data);
buffWriter.flush();
buffWriter.close();
System.out.println(filePath + " has been created.");
}catch(IOException ex)
{
System.err.println(ex.getMessage());
}
}
}
for more details visit https://www.dev2qa.com/convert-excel-to-json-in-java-example/

How to avoid skipping blank rows or columns in Apache POI

When I parse the file using Apace POI, the empty rows are getting skipped and a List of String arrays with non-empty rows are being returned.
How can I tell the API, not to skip reading the empty row or columns ?
The code to read is somehow skipping the rows with no data.
XExcelFileReader fileReader = new XExcelFileReader(excelByteArray, sheetFromWhichToRead);
dataFromFile = fileReader.readRows();
is used to read the data from the class XExcelFileReader. The variable dataFromFile is a List of String array.
This is the code to read the data row:
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
/**
* This class is responsible for reading the row contents for a given byte array and sheet name
*/
public class XExcelFileReader {
/**
* This is the Row Num of the current row that was read
*/
private int rowNum = 0;
/**
* The OPCPackage is the package used to laod the Input Stream used for only .xlsx Files
*/
private OPCPackage opcPkg;
/**
* These are the String Tables that are read from the Excel File
*/
private ReadOnlySharedStringsTable stringsTable;
/**
* The XML Streaming API will be used
*/
private XMLStreamReader xmlReader;
/** The styles table which has formatting information about cells. */
private StylesTable styles;
/**
* #param excelByteArray the excel byte array
* #param sheetFromWhichToRead the excel sheet from which to read
* #throws Exception the exception
*/
public XExcelFileReader(final byte[] excelByteArray, final String sheetFromWhichToRead) throws Exception {
InputStream excelStream = new ByteArrayInputStream(excelByteArray);
opcPkg = OPCPackage.open(excelStream);
this.stringsTable = new ReadOnlySharedStringsTable(opcPkg);
XSSFReader xssfReader = new XSSFReader(opcPkg);
styles = xssfReader.getStylesTable();
XMLInputFactory factory = XMLInputFactory.newInstance();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
InputStream inputStream = null;
while (iter.hasNext()) {
inputStream = iter.next();
String tempSheetName = iter.getSheetName();
if (StringUtils.isNotEmpty(tempSheetName)) {
tempSheetName = tempSheetName.trim();
if (tempSheetName.equals(sheetFromWhichToRead)) {
break;
}
}
}
xmlReader = factory.createXMLStreamReader(inputStream);
while (xmlReader.hasNext()) {
xmlReader.next();
if (xmlReader.isStartElement()) {
if (xmlReader.getLocalName().equals("sheetData")) {
break;
}
}
}
}
/**
* #return rowNum
*/
public final int rowNum() {
return rowNum;
}
/**
* #return List<String[]> List of String array which can hold the content
* #throws XMLStreamException the XMLStreamException
*/
public final List<String[]> readRows() throws XMLStreamException {
String elementName = "row";
List<String[]> dataRows = new ArrayList<String[]>();
while (xmlReader.hasNext()) {
xmlReader.next();
if (xmlReader.isStartElement()) {
if (xmlReader.getLocalName().equals(elementName)) {
rowNum++;
dataRows.add(getDataRow());
// TODO need to see if the batch Size is required
// if (dataRows.size() == batchSize)
// break;
}
}
}
return dataRows;
}
/**
* #return String [] of Row Data
* #throws XMLStreamException the XMLStreamException
*/
private String[] getDataRow() throws XMLStreamException {
List<String> rowValues = new ArrayList<String>();
while (xmlReader.hasNext()) {
xmlReader.next();
if (xmlReader.isStartElement()) {
if (xmlReader.getLocalName().equals("c")) {
CellReference cellReference = new CellReference(xmlReader.getAttributeValue(null, "r"));
// Fill in the possible blank cells!
while (rowValues.size() < cellReference.getCol()) {
rowValues.add("");
}
String cellType = xmlReader.getAttributeValue(null, "t");
String cellStyleStr = xmlReader.getAttributeValue(null, "s");
rowValues.add(getCellValue(cellType, cellStyleStr));
}
} else if (xmlReader.isEndElement() && xmlReader.getLocalName().equals("row")) {
break;
}
}
return rowValues.toArray(new String[rowValues.size()]);
}
/**
* #param cellType the cell type
* #param cellStyleStr the cell style
* #return cell content the cell value
* #throws XMLStreamException the XMLStreamException
*/
private String getCellValue(final String cellType, final String cellStyleStr) throws XMLStreamException {
String value = ""; // by default
while (xmlReader.hasNext()) {
xmlReader.next();
if (xmlReader.isStartElement()) {
if (xmlReader.getLocalName().equals("v")) {
if (cellType != null && cellType.equals("s")) {
int idx = Integer.parseInt(xmlReader.getElementText());
String s = stringsTable.getEntryAt(idx);
return new XSSFRichTextString(s).toString();
}
if (cellStyleStr != null) {
String cellValue = xmlReader.getElementText();
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = styles.getStyleAt(styleIndex);
short formatIndex = style.getDataFormat();
if (!isValidDouble(cellValue)) {
return cellValue;
}
double doubleVal = Double.valueOf(cellValue);
boolean isValidExcelDate = HSSFDateUtil.isInternalDateFormat(formatIndex);
Date date = null;
if (isValidExcelDate) {
date = HSSFDateUtil.getJavaDate(doubleVal);
String dateStr = dateAsString(date);
return dateStr;
}
if (!(doubleVal == Math.floor(doubleVal))) {
return Double.toString(doubleVal);
}
return cellValue;
}
else {
return xmlReader.getElementText();
}
}
} else if (xmlReader.isEndElement() && xmlReader.getLocalName().equals("c")) {
break;
}
}
return value;
}
/**
* To check whether the incoming value can be used in the Double utility method Double.valueOf() to prevent
* NumberFormatException.
* #param stringVal - String to be validated.
* #return - true if it is a valid String which can be passed into Double.valueOf method. <br/> For more information
* refer- <a>https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#valueOf(java.lang.String)</a>
*/
private boolean isValidDouble(String stringVal) {
final String Digits = "(\\p{Digit}+)";
final String HexDigits = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally
// signed decimal integer.
final String Exp = "[eE][+-]?" + Digits;
final String fpRegex = ("[\\x00-\\x20]*" + // Optional leading "whitespace"
"[+-]?(" + // Optional sign character
"NaN|" + // "NaN" string
"Infinity|" + // "Infinity" string
// A decimal floating-point string representing a finite positive
// number without a leading sign has at most five basic pieces:
// Digits . Digits ExponentPart FloatTypeSuffix
//
// Since this method allows integer-only strings as input
// in addition to strings of floating-point literals, the
// two sub-patterns below are simplifications of the grammar
// productions from the Java Language Specification, 2nd
// edition, section 3.10.2.
// Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
"(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +
// . Digits ExponentPart_opt FloatTypeSuffix_opt
"(\\.(" + Digits + ")(" + Exp + ")?)|" +
// Hexadecimal strings
"((" +
// 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "(\\.)?)|" +
// 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
"(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
")[pP][+-]?" + Digits + "))" + "[fFdD]?))" + "[\\x00-\\x20]*");// Optional trailing "whitespace"
if (Pattern.matches(fpRegex, stringVal))
return true;
else {
return false;
}
}
/**
* Date as string.
* #param date the date
* #return the string
*/
public static String dateAsString(final Date date) {
String dateAsString = null;
if (date != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
dateAsString = sdf.format(date);
}
return dateAsString;
}
#Override
protected final void finalize() throws Throwable {
if (opcPkg != null) {
opcPkg.close();
}
super.finalize();
}
}
I want the Empty row also to be part of the List of String array. Just that the String array will be empty.
If it is in the Excel like:
First Row
<< No Data >>
Third Row
then the List should be
dataFromFile
0 ->[First Row]
1 ->[]
2 ->[Third Row]
Here is what the Busy Developers Guide on the POI site says about reading sheets with missing rows:
for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
Row r = sheet.getRow(rowNum);
if (r == null) {
// This whole row is empty
// Handle it as needed
continue;
}
int lastColumn = Math.max(r.getLastCellNum(), MY_MINIMUM_COLUMN_COUNT);
for (int cn = 0; cn < lastColumn; cn++) {
Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
if (c == null) {
// The spreadsheet is empty in this cell
} else {
// Do something useful with the cell's contents
}
}
}
You really can get a lot of your answers there. You shouldn't ever have to parse the XML directly. Even things that are missing from the high level usermodel usually have a way to get at it through the CT classes generated by XMLBeans.

Start reading an Excel sheet at a specified row

I am reading an Excel file using POI's XSSF and SAX (Event API). The Excel sheet has thousands of rows so this is the only way that I have found to have good performance. Now I would like to read Excel file from one particularly row, for example row 6 because these Excel files are updated every day and I store the last row that I have already stored so I can read only the new rows.
How can I start from one row?
private void getExcelField(AcquisitionForm acquisitionForm) throws ExcelReadException, IOException{
InputStream stream=null;
OPCPackage p=null;
try{
p = OPCPackage.open(acquisitionForm.getDatatablePath(), PackageAccess.READ);
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(p);
XSSFReader xssfReader = new XSSFReader(p);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
int index = 0;
//Test with one sheet
iter.hasNext();
//(iter.hasNext()) {
stream = iter.next();
String sheetName = iter.getSheetName();
processSheet(styles, strings, stream, acquisitionForm);
stream.close();
//++index;
//}
p.close();
}catch(Exception e){
throw new ExcelReadException("An error occured during excel file reading ", e);
}finally{
if (stream!=null)
stream.close();
if (p!=null)
p.close();
//++index;
// }
}
}
/**
* Parses and shows the content of one sheet
* using the specified styles and shared-strings tables.
* #param styles
* #param strings
* #param sheetInputStream
* #throws ExcelReadException
*/
private void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream, AcquisitionForm acquisitionForm) throws Exception {
InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
//ContentHandler handler = new MyXSSFSheetHandler(styles, strings);
MyXSSFSheetHandler handler = new MyXSSFSheetHandler(styles, strings,databaseAcquisitionServices, acquisitionForm);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
}
MyXSSFSheetHandler
public MyXSSFSheetHandler(StylesTable styles, ReadOnlySharedStringsTable strings,DatabaseAcquisitionServices databaseAcquisitionServices, AcquisitionForm acquisitionForm, int sheetIndex) {
this.stylesTable = styles;
this.sharedStringsTable = strings;
this.formatter = new DataFormatter();
this.value = new StringBuffer();
this.nextDataType = XssfDataType.NUMBER;
this.databaseAcquisitionServices=databaseAcquisitionServices;
this.acquisitionForm=acquisitionForm;
this.sheetIndex = sheetIndex;
}
/**
*
*/
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if ("inlineStr".equals(name) || "v".equals(name)) {
vIsOpen = true;
// Clear contents cache
value.setLength(0);
}
// c => cell
else if ("c".equals(name)) {
// Get the cell reference
cellCoordinate = attributes.getValue("r");
int firstDigit = -1;
for (int c = 0; c < cellCoordinate.length(); ++c) {
if (Character.isDigit(cellCoordinate.charAt(c))) {
firstDigit = c;
break;
}
}
thisColumn = nameToColumn(cellCoordinate.substring(0, firstDigit));
// Set up defaults.
this.nextDataType = XssfDataType.NUMBER;
this.formatIndex = -1;
this.formatString = null;
String cellType = attributes.getValue("t");
String cellStyleStr = attributes.getValue("s");
if ("b".equals(cellType)) {
nextDataType = XssfDataType.BOOL;
} else if ("e".equals(cellType)) {
nextDataType = XssfDataType.ERROR;
} else if ("inlineStr".equals(cellType)) {
nextDataType = XssfDataType.INLINESTR;
} else if ("s".equals(cellType)) {
nextDataType = XssfDataType.SSTINDEX;
} else if ("str".equals(cellType)) {
nextDataType = XssfDataType.FORMULA;
} else if (cellStyleStr != null) {
// It's a number, but almost certainly one
// with a special style or format
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
this.formatIndex = style.getDataFormat();
this.formatString = style.getDataFormatString();
if (this.formatString == null) {
this.formatString = BuiltinFormats.getBuiltinFormat(this.formatIndex);
}
}
}
}
/*
* (non-Javadoc)
* #see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String name)
throws SAXException {
String cellValue = null;
//String thisStr = null;
// v => contents of a cell
if ("v".equals(name)) {
// Process the value contents as required.
// Do now, as characters() may be called more than once
switch (nextDataType) {
case BOOL:
char first = value.charAt(0);
//thisStr = first == '0' ? "FALSE" : "TRUE";
//cellValue= new Boolean(first =='0' ? false: true);
cellValue=first == '0' ? "false" : "true";
break;
case ERROR:
//thisStr = "\"ERROR:" + value.toString() + '"';
cellValue=new String(value.toString());
break;
case FORMULA:
// A formula could result in a string value,
// so always add double-quote characters.
//thisStr = '"' + value.toString() + '"';
cellValue=new String(value.toString());
break;
case INLINESTR:
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
//thisStr = '"' + rtsi.toString() + '"';
cellValue=new String(rtsi.toString());
break;
case SSTINDEX:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss = new XSSFRichTextString(sharedStringsTable.getEntryAt(idx));
// thisStr = '"' + rtss.toString() + '"';
cellValue=new String(rtss.toString());
}
catch (NumberFormatException ex) {
System.out.println("Failed to parse SST index '" + sstIndex + "': " + ex.toString());
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null && n.length() > 0){
cellValue = formatter.formatRawCellContents(Double.parseDouble(n), this.formatIndex, this.formatString);
//cellValue=new Double(Double.parseDouble(n));
}
else{
//thisStr = n;
cellValue=new String(n);
}
break;
default:
cellValue="";
//thisStr = "(TODO: Unexpected type: " + nextDataType + ")";
break;
}
// Output after we've seen the string contents
// Emit commas for any fields that were missing on this row
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
// for (int i = lastColumnNumber; i < thisColumn; ++i){
// System.out.print(',');
// }
// Might be the empty string.
rowValues.put(cellCoordinate,cellValue);
//System.out.print(cellValue);
// Update column
if (thisColumn > -1)
lastColumnNumber = thisColumn;
} else if ("row".equals(name)) {
// We're onto a new row
//I have to pass new HashMap because otherwise all the map into archiveAcquisition have the same values
databaseAcquisitionServices.archiveAcquisition(new TreeMap<>(rowValues), rowCounter, acquisitionForm, sheetIndex);
//Clear the structure used to store row data
rowValues.clear();
rowCounter++;
//System.out.println();
lastColumnNumber = -1;
}
}
/**
* Captures characters only if a suitable element is open.
* Originally was just "v"; extended for inlineStr also.
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
if (vIsOpen)
value.append(ch, start, length);
}
/**
* Converts an Excel column name like "C" to a zero-based index.
*
* #param name
* #return Index corresponding to the specified name
*/
private int nameToColumn(String name) {
int column = -1;
for (int i = 0; i < name.length(); ++i) {
int c = name.charAt(i);
column = (column + 1) * 26 + c - 'A';
}
return column;
}
You will likely need to count the number of rows that you see in a class derived from SheetContentsHandler, I don't think you need to have a separate XSSFSheetHAndler, I would rather use the default one and only have a dervied SheetContentsHandler which has callback-methods for all the things that you are interested in, e.g. startRow, endRow, cell.
You can take a look at the XLSX2CSV sample for an example of how streaming reading of XLSX files can be done, especially how the class SheetToCSV is used to get calls for each row/cell, you could e.g. use something like if (currentRow < startRow) { return } in the method cell() to skip rows.
The cell-method is called with a parameter String cellReference which can be used to retrieve the row/cell coordinates via new CellReference(cellReference).getCol() and new CellReference(cellReference).getRow().

Embed files into Excel using Apache POI

I am exporting data to Excel file using Apache POI. In one weird requirement, I need to embed one file in the Excel using this POI. I have the file, and can be taken into streams or as byte arrays. After googling for much time, I am in a doubt whether POI really supports my requirement. Can we embed files into Excel? :-(
Cheers,
Anoop
Ok, this took very long to finally work out, as there were a few things which didn't look very important at the beginning, but actually corrupted the file when they haven't been set right - especially in the Ole10Native wrapper, part of the unknown2 field actually contained the size (in bytes) of the following command string.
But first things first:
When you want to embed arbitrary files into one of the office formats, your best bet is to use the OLE 1.0 packager. It will be typically used, when you select insert->object from file.
So I've re-engineered an Excel 2003 file containing a PPT. As mentioned in my comment above, Excel will store its embedded objects in DirectoryNodes named "MBD....". In case of a Ole 1.0 Packager object, the interesting data will be found in the \1Ole10Native entry.
When you've inserted the data, you'll need to link it somehow in the Excel sheet. This is done by an EscherObject similar to a picture entry with additional attached records.
Apart from the many undocumented flags, there were a few things which puzzled me:
are the storage ids for the embedded objects just randomly assigned or is there some kind of number system?
I've searched for a more detailed description of the Ole10Native wrapper and especially for the ole 1.0 packager format, but apart of the M$ docu which sketchily handles it as one big byte chunk, most sources did some reengineering which looked very similar to the poi Ole10Native class ... of course the idea to check the libre office source came also to mind, but I have to admit the ones I've checked, only confused me :(
which one is the right clsid for the embedded object? ... i.e. for powerpoint there are quite a few. So if in doubt, obviously you'll need to lookup the clsid by a previously saved file from Office
Excel 2010 generates Biff8 files which embedded objects can't be opened by Libre Office!?!
the ole10Native object contains among other things a command line entry. would be interesting if someone can start other things than the embedded object with it ...
the BiffViewer crashed when I've used preview images bigger than some chunk size (~6kb). So either images would need to be chunked or the BiffViewer implementation is wrong ... this also caused some confusing for a while ...
Tested with POI 3.9, Libre Office 4.0, Office 2010 (I don't have Office 2003 anymore ...)
import java.awt.Color;
import java.io.*;
import java.lang.reflect.*;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import org.apache.poi.ddf.*;
import org.apache.poi.hpsf.ClassID;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.model.ShapeTypes;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hssf.dev.BiffViewer;
import org.apache.poi.hssf.model.*;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.*;
#SuppressWarnings("unused")
public class PoiOlePptInXls {
public static final OleType PACKAGE = new OleType("{0003000C-0000-0000-C000-000000000046}");
public static final OleType PPT_SHOW = new OleType("{64818D10-4F9B-11CF-86EA-00AA00B929E8}");
public static final OleType XLS_WORKBOOK = new OleType("{00020841-0000-0000-C000-000000000046}");
public static final OleType TXT_ONLY = new OleType("{5e941d80-bf96-11cd-b579-08002b30bfeb}"); // ???
static class OleType {
final String classId;
OleType(String classId) {
this.classId = classId;
}
ClassID getClassID() {
ClassID cls = new ClassID();
byte clsBytes[] = cls.getBytes();
String clsStr = classId.replaceAll("[{}-]", "");
for (int i=0; i<clsStr.length(); i+=2) {
clsBytes[i/2] = (byte)Integer.parseInt(clsStr.substring(i, i+2), 16);
}
return cls;
}
}
public static void main(String[] args) throws Exception {
POIFSFileSystem poifs = new POIFSFileSystem();
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
int previewIdxPpt = generatePreview(wb, "application/powerpoint");
int storageIdPpt = packageOleData(poifs, getSamplePPT(), "Example.ppt", "Example.ppt", "Example.ppt");
int previewIdxXls = generatePreview(wb, "application/excel");
int storageIdXls = packageOleData(poifs, getSampleXLS(), "Example.xls", "Example.xls", "Example.xls");
int previewIdxTxt = generatePreview(wb, "text/plain");
int storageIdTxt = packageOleData(poifs, getSampleTXT(), "Example.txt", "Example.txt", "Example.txt");
int rowoffset = 5;
int coloffset = 5;
CreationHelper ch = wb.getCreationHelper();
HSSFClientAnchor anchor = (HSSFClientAnchor)ch.createClientAnchor();
anchor.setAnchor((short)(2+coloffset), 1+rowoffset, 0, 0, (short)(3+coloffset), 5+rowoffset, 0, 0);
anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
HSSFObjectData oleShape = createObjectData(poifs, storageIdPpt, 1, anchor, previewIdxPpt);
addShape(patriarch, oleShape);
anchor = (HSSFClientAnchor)ch.createClientAnchor();
anchor.setAnchor((short)(5+coloffset), 1+rowoffset, 0, 0, (short)(6+coloffset), 5+rowoffset, 0, 0);
anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
oleShape = createObjectData(poifs, storageIdXls, 2, anchor, previewIdxXls);
addShape(patriarch, oleShape);
anchor = (HSSFClientAnchor)ch.createClientAnchor();
anchor.setAnchor((short)(3+coloffset), 10+rowoffset, 0, 0, (short)(5+coloffset), 11+rowoffset, 0, 0);
anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
oleShape = createObjectData(poifs, storageIdTxt, 3, anchor, previewIdxTxt);
addShape(patriarch, oleShape);
anchor = (HSSFClientAnchor)ch.createClientAnchor();
anchor.setAnchor((short)(1+coloffset), -2+rowoffset, 0, 0, (short)(7+coloffset), 14+rowoffset, 0, 0);
anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
HSSFSimpleShape circle = patriarch.createSimpleShape(anchor);
circle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
circle.setNoFill(true);
poifs.getRoot().createDocument("Workbook", new ByteArrayInputStream(wb.getBytes()));
FileOutputStream fos = new FileOutputStream("ole_ppt_in_xls.xls");
poifs.writeFilesystem(fos);
fos.close();
}
static void addShape(HSSFPatriarch patriarch, HSSFShape shape) throws Exception {
patriarch.addShape(shape);
Method m = HSSFPatriarch.class.getDeclaredMethod("onCreate", HSSFShape.class);
m.setAccessible(true);
m.invoke(patriarch, shape);
}
static HSSFObjectData createObjectData(POIFSFileSystem poifs, int storageId, int objectIdx, HSSFClientAnchor anchor, int previewIdx) {
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord ftCmo = new CommonObjectDataSubRecord();
ftCmo.setObjectType(CommonObjectDataSubRecord.OBJECT_TYPE_PICTURE);
ftCmo.setObjectId(objectIdx);
ftCmo.setLocked(true);
ftCmo.setPrintable(true);
ftCmo.setAutofill(true);
ftCmo.setAutoline(true);
ftCmo.setReserved1(0);
ftCmo.setReserved2(0);
ftCmo.setReserved3(0);
obj.addSubRecord(ftCmo);
obj.addSubRecord(SubRecord.createSubRecord(new LittleEndianByteArrayInputStream(new byte[]{7,0,2,0,2,0}), 0));
obj.addSubRecord(SubRecord.createSubRecord(new LittleEndianByteArrayInputStream(new byte[]{8,0,2,0,1,0}), 0));
EmbeddedObjectRefSubRecord ftPictFmla;
try {
Constructor<EmbeddedObjectRefSubRecord> con = EmbeddedObjectRefSubRecord.class.getDeclaredConstructor();
con.setAccessible(true);
ftPictFmla = con.newInstance();
} catch (Exception e) {
throw new RuntimeException("oops", e);
}
setField(ftPictFmla, "field_2_unknownFormulaData", new byte[]{2, 0, 0, 0, 0});
setField(ftPictFmla, "field_4_ole_classname", "Paket");
setField(ftPictFmla, "field_5_stream_id", (Integer)storageId);
obj.addSubRecord(ftPictFmla);
obj.addSubRecord(new EndSubRecord());
// create temporary picture, but don't attach it.
// It's neccessary to create the sp-container, which need to be minimal modified
// for oleshapes
HSSFPicture shape = new HSSFPicture(null, anchor);
EscherContainerRecord spContainer;
try {
Method m = HSSFPicture.class.getDeclaredMethod("createSpContainer");
m.setAccessible(true);
spContainer = (EscherContainerRecord)m.invoke(shape);
} catch (Exception e) {
throw new RuntimeException("oops", e);
}
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(spRecord.getFlags() | EscherSpRecord.FLAG_OLESHAPE);
spRecord.setShapeType((byte)0x4B);
EscherOptRecord optRecord = spContainer.getChildById(EscherOptRecord.RECORD_ID);
EscherProperty ep = new EscherSimpleProperty(EscherProperties.BLIP__PICTUREID, false, false, 1);
optRecord.addEscherProperty(ep);
DirectoryEntry oleRoot;
try {
oleRoot = (DirectoryEntry)poifs.getRoot().getEntry(formatStorageId(storageId));
} catch (FileNotFoundException e) {
throw new RuntimeException("oops", e);
}
HSSFObjectData oleShape = new HSSFObjectData(spContainer, obj, oleRoot);
oleShape.setPictureIndex(previewIdx);
return oleShape;
}
static void setField(Object clazz, String fieldname, Object value) {
try {
Field f = clazz.getClass().getDeclaredField(fieldname);
f.setAccessible(true);
f.set(clazz, value);
} catch (Exception e) {
throw new RuntimeException("oops", e);
}
}
static void addOleStreamEntry(DirectoryEntry dir) throws IOException {
final String OLESTREAM_NAME = "\u0001Ole";
if (!dir.hasEntry(OLESTREAM_NAME)) {
// the following data was taken from an example libre office document
// beside this "\u0001Ole" record there were several other records, e.g. CompObj,
// OlePresXXX, but it seems, that they aren't neccessary
byte oleBytes[] = { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
dir.createDocument(OLESTREAM_NAME, new ByteArrayInputStream(oleBytes));
}
}
static String formatStorageId(int storageId) {
return String.format("MBD%1$08X", storageId);
}
static int packageOleData(POIFSFileSystem poifs, byte oleData[], String label, String fileName, String command) throws IOException {
DirectoryNode root = poifs.getRoot();
// get free MBD-Node
int storageId = 0;
DirectoryEntry oleDir = null;
do {
String storageStr = formatStorageId(++storageId);
if (!root.hasEntry(storageStr)) {
oleDir = root.createDirectory(storageStr);
oleDir.setStorageClsid(PACKAGE.getClassID());
}
} while (oleDir == null);
addOleStreamEntry(oleDir);
Ole10Native2 oleNative = new Ole10Native2();
oleNative.setLabel(label);
oleNative.setFileName(fileName);
oleNative.setCommand(command);
oleNative.setDataBuffer(oleData);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
oleNative.writeOut(bos);
byte buf1[] = bos.toByteArray();
oleDir.createDocument(Ole10Native2.OLE10_NATIVE, new ByteArrayInputStream(buf1));
return storageId;
}
static byte[] getSamplePPT() {
HSLFSlideShow ss = HSLFSlideShow.create();
SlideShow ppt = new SlideShow(ss);
Slide slide = ppt.createSlide();
AutoShape sh1 = new AutoShape(ShapeTypes.Star32);
sh1.setAnchor(new java.awt.Rectangle(50, 50, 100, 200));
sh1.setFillColor(Color.red);
slide.addShape(sh1);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ppt.write(bos);
POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
poifs.getRoot().setStorageClsid(PPT_SHOW.getClassID());
bos.reset();
poifs.writeFilesystem(bos);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("bla", e);
}
}
static byte[] getSampleXLS() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
sheet.createRow(5).createCell(2).setCellValue("yo dawg i herd you like embeddet objekts, so we put a ole in your ole so you can save a file while you save a file");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
wb.write(bos);
POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
poifs.getRoot().setStorageClsid(XLS_WORKBOOK.getClassID());
bos.reset();
poifs.writeFilesystem(bos);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("bla", e);
}
}
static byte[] getSampleTXT() {
return "All your base are belong to us".getBytes();
}
/**
* to be defined, how to create a preview image for a start, I've taken just
* a dummy image, which will be replaced, when the user activates the ole
* object
*
* not really an alternativ:
* http://stackoverflow.com/questions/16704624/how-
* to-print-a-workbook-file-made-using-apache-poi-and-java
*
* #return image index of the preview image
*/
static int generatePreview(HSSFWorkbook workbook, String mimetype) {
try {
String url = "";
if ("application/powerpoint".equals(mimetype)) {
url = "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/LibreOffice_Impress_icon_3.3.1_48_px.svg/40px-LibreOffice_Impress_icon_3.3.1_48_px.svg.png";
} else if ("application/excel".equals(mimetype)) {
url = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/LibreOffice_Calc_icon_3.3.1_48_px.svg/40px-LibreOffice_Calc_icon_3.3.1_48_px.svg.png";
} else if ("text/plain".equals(mimetype)) {
url = "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/LibreOffice_Writer_icon_3.3.1_48_px.svg/40px-LibreOffice_Writer_icon_3.3.1_48_px.svg.png";
}
InputStream is = new URL(url).openStream();
byte previewImg[] = IOUtils.toByteArray(is);
is.close();
int pictIdx = workbook.addPicture(previewImg, HSSFWorkbook.PICTURE_TYPE_PNG);
return pictIdx;
} catch (IOException e) {
throw new RuntimeException("not really?", e);
}
}
/*
* Helper - determine length of zero terminated string (ASCIIZ).
*/
private static int getStringLength(byte[] data, int ofs) {
int len = 0;
while (len + ofs < data.length && data[ofs + len] != 0) {
len++;
}
len++;
return len;
}
}
The adapted Ole10Native class of POI with write-support:
import java.io.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.util.*;
/**
* Represents an Ole10Native record which is wrapped around certain binary files
* being embedded in OLE2 documents.
*
* #author Rainer Schwarze
*/
public class Ole10Native2 {
public static final String OLE10_NATIVE = "\u0001Ole10Native";
protected static final String ISO1 = "ISO-8859-1";
// (the fields as they appear in the raw record:)
protected int totalSize; // 4 bytes, total size of record not including this
// field
protected short flags1 = 2; // 2 bytes, unknown, mostly [02 00]
protected String label; // ASCIIZ, stored in this field without the
// terminating zero
protected String fileName; // ASCIIZ, stored in this field without the
// terminating zero
protected short flags2 = 0; // 2 bytes, unknown, mostly [00 00]
protected short unknown1 = 3;
protected String command; // ASCIIZ, stored in this field without the
// terminating zero
protected byte[] dataBuffer; // varying size, the actual native data
protected short flags3 = 0; // some final flags? or zero terminators?,
// sometimes not there
/**
* Creates an instance of this class from an embedded OLE Object. The OLE
* Object is expected to include a stream "{01}Ole10Native" which
* contains the actual data relevant for this class.
*
* #param poifs
* POI Filesystem object
* #return Returns an instance of this class
* #throws IOException
* on IO error
* #throws Ole10NativeException
* on invalid or unexcepted data format
*/
public static Ole10Native2 createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
return createFromEmbeddedOleObject(poifs.getRoot());
}
/**
* Creates an instance of this class from an embedded OLE Object. The OLE
* Object is expected to include a stream "{01}Ole10Native" which
* contains the actual data relevant for this class.
*
* #param directory
* POI Filesystem object
* #return Returns an instance of this class
* #throws IOException
* on IO error
* #throws Ole10NativeException
* on invalid or unexcepted data format
*/
public static Ole10Native2 createFromEmbeddedOleObject(DirectoryNode directory) throws IOException, Ole10NativeException {
boolean plain = false;
try {
directory.getEntry("\u0001Ole10ItemName");
plain = true;
} catch (FileNotFoundException ex) {
plain = false;
}
DocumentEntry nativeEntry = (DocumentEntry) directory.getEntry(OLE10_NATIVE);
byte[] data = new byte[nativeEntry.getSize()];
directory.createDocumentInputStream(nativeEntry).read(data);
return new Ole10Native2(data, 0, plain);
}
/**
* Creates an instance and fills the fields based on the data in the given
* buffer.
*
* #param data
* The buffer containing the Ole10Native record
* #param offset
* The start offset of the record in the buffer
* #throws Ole10NativeException
* on invalid or unexcepted data format
*/
public Ole10Native2(byte[] data, int offset) throws Ole10NativeException {
this(data, offset, false);
}
/**
* Creates an instance and fills the fields based on the data in the given
* buffer.
*
* #param data
* The buffer containing the Ole10Native record
* #param offset
* The start offset of the record in the buffer
* #param plain
* Specified 'plain' format without filename
* #throws Ole10NativeException
* on invalid or unexcepted data format
*/
public Ole10Native2(byte[] data, int offset, boolean plain) throws Ole10NativeException {
int ofs = offset; // current offset, initialized to start
if (data.length < offset + 2) {
throw new Ole10NativeException("data is too small");
}
totalSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
if (plain) {
dataBuffer = new byte[totalSize - 4];
System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
int dataSize = totalSize - 4;
byte[] oleLabel = new byte[8];
System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
label = "ole-" + HexDump.toHex(oleLabel);
fileName = label;
command = label;
} else {
flags1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
int len = getStringLength(data, ofs);
label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
len = getStringLength(data, ofs);
fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
flags2 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
unknown1 = LittleEndian.getShort(data, ofs);
ofs += LittleEndianConsts.SHORT_SIZE;
len = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
ofs += len;
if (totalSize < ofs) {
throw new Ole10NativeException("Invalid Ole10Native");
}
int dataSize = LittleEndian.getInt(data, ofs);
ofs += LittleEndianConsts.INT_SIZE;
if (dataSize < 0 || totalSize - (ofs - LittleEndianConsts.INT_SIZE) < dataSize) {
throw new Ole10NativeException("Invalid Ole10Native");
}
dataBuffer = new byte[dataSize];
System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
ofs += dataSize;
// if (unknown1.length > 0) {
// flags3 = LittleEndian.getShort(data, ofs);
// ofs += LittleEndianConsts.SHORT_SIZE;
// } else {
// flags3 = 0;
// }
}
}
public Ole10Native2() {}
/*
* Helper - determine length of zero terminated string (ASCIIZ).
*/
private static int getStringLength(byte[] data, int ofs) {
int len = 0;
while (len + ofs < data.length && data[ofs + len] != 0) {
len++;
}
len++;
return len;
}
/**
* Returns the value of the totalSize field - the total length of the
* structure is totalSize + 4 (value of this field + size of this field).
*
* #return the totalSize
*/
public int getTotalSize() {
return totalSize;
}
/**
* Returns flags1 - currently unknown - usually 0x0002.
*
* #return the flags1
*/
public short getFlags1() {
return flags1;
}
/**
* Returns the label field - usually the name of the file (without
* directory) but probably may be any name specified during
* packaging/embedding the data.
*
* #return the label
*/
public String getLabel() {
return label;
}
/**
* Returns the fileName field - usually the name of the file being embedded
* including the full path.
*
* #return the fileName
*/
public String getFileName() {
return fileName;
}
/**
* Returns flags2 - currently unknown - mostly 0x0000.
*
* #return the flags2
*/
public short getFlags2() {
return flags2;
}
/**
* Returns unknown1 field - currently unknown.
*
* #return the unknown1
*/
public short getUnknown1() {
return unknown1;
}
/**
* Returns the unknown2 field - currently being a byte[3] - mostly {0, 0,
* 0}.
*
* #return the unknown2
*/
// public short getUnknown2() {
// return unknown2;
// }
/**
* Returns the command field - usually the name of the file being embedded
* including the full path, may be a command specified during embedding the
* file.
*
* #return the command
*/
public String getCommand() {
return command;
}
/**
* Returns the size of the embedded file. If the size is 0 (zero), no data
* has been embedded. To be sure, that no data has been embedded, check
* whether {#link #getDataBuffer()} returns <code>null</code>.
*
* #return the dataSize
*/
public int getDataSize() {
return dataBuffer.length;
}
/**
* Returns the buffer containing the embedded file's data, or
* <code>null</code> if no data was embedded. Note that an embedding may
* provide information about the data, but the actual data is not included.
* (So label, filename etc. are available, but this method returns
* <code>null</code>.)
*
* #return the dataBuffer
*/
public byte[] getDataBuffer() {
return dataBuffer;
}
/**
* Returns the flags3 - currently unknown.
*
* #return the flags3
*/
public short getFlags3() {
return flags3;
}
/**
* Have the contents printer out into an OutputStream, used when writing a
* file back out to disk (Normally, atom classes will keep their bytes
* around, but non atom classes will just request the bytes from their
* children, then chuck on their header and return)
*/
public void writeOut(OutputStream out) throws IOException {
byte intbuf[] = new byte[LittleEndianConsts.INT_SIZE];
byte shortbuf[] = new byte[LittleEndianConsts.SHORT_SIZE];
byte bytebuf[] = new byte[LittleEndianConsts.BYTE_SIZE];
// LittleEndian.putInt(_header, 4, _data.length);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(intbuf); // total size, will be determined later ..
LittleEndian.putShort(shortbuf, 0, getFlags1());
bos.write(shortbuf);
bos.write(getLabel().getBytes(ISO1));
bos.write(0);
bos.write(getFileName().getBytes(ISO1));
bos.write(0);
LittleEndian.putShort(shortbuf, 0, getFlags2());
bos.write(shortbuf);
LittleEndian.putShort(shortbuf, 0, getUnknown1());
bos.write(shortbuf);
LittleEndian.putInt(intbuf, 0, getCommand().length()+1);
bos.write(intbuf);
bos.write(getCommand().getBytes(ISO1));
bos.write(0);
LittleEndian.putInt(intbuf, 0, getDataBuffer().length);
bos.write(intbuf);
bos.write(getDataBuffer());
LittleEndian.putShort(shortbuf, 0, getFlags3());
bos.write(shortbuf);
// update total size - length of length-field (4 bytes)
byte data[] = bos.toByteArray();
totalSize = data.length - LittleEndianConsts.INT_SIZE;
LittleEndian.putInt(data, 0, totalSize);
out.write(data);
}
public void setFlags1(short flags1) {
this.flags1 = flags1;
}
public void setFlags2(short flags2) {
this.flags2 = flags2;
}
public void setFlags3(short flags3) {
this.flags3 = flags3;
}
public void setLabel(String label) {
this.label = label;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public void setCommand(String command) {
this.command = command;
}
public void setUnknown1(short unknown1) {
this.unknown1 = unknown1;
}
// public void setUnknown2(short unknown2) {
// this.unknown2 = unknown2;
// }
public void setDataBuffer(byte dataBuffer[]) {
this.dataBuffer = dataBuffer;
}
}
This page of the online documentation might answer your question:
http://poi.apache.org/components/poifs/embeded.html

Getting Apache POI java.lang.IllegalStateException: Zip File is closed when trying to read a xlsx file

I am getting java.lang.IllegalStateException: Zip File is closed when i try to read a xlsx file. The code is being accessed from a spring based app. I am using apache poi 3.9. With apache POI 3.8 i was getting Can't read file. The same code works fine when ran from my eclipse locally, but i get the exception when the app is deployed on my websphere server and is accessed when hosted on websphere. Can anyone please let me know what the problem is? The source code can be found below.
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.validator.GenericValidator;
import org.apache.log4j.Logger;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class XSSFListenerUtil {
private static List<String> allColValList = null;
private static boolean invalidTemplate = false;
private final static Logger log = Logger.getLogger(HSSFListenerUtil.class.getName()); // logger for the process.
private static BaseViewBean baseViewBean$Session;
/**
* The type of the data value is indicated by an attribute on the cell.
* The value is usually in a "v" element within the cell.
*/
enum xssfDataType {
BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER,
}
class MyXSSFSheetHandler extends DefaultHandler {
/**
* Table with styles
*/
private StylesTable stylesTable;
/**
* Table with unique strings
*/
private ReadOnlySharedStringsTable sharedStringsTable;
/**
* Destination for data
*/
//private final PrintStream output;
/**
* Number of columns to read starting with leftmost
*/
private final int minColumnCount;
// Set when V start element is seen
private boolean vIsOpen;
// Set when cell start element is seen;
// used when cell close element is seen.
private xssfDataType nextDataType;
// Used to format numeric cell values.
private short formatIndex;
private String formatString;
private final DataFormatter formatter;
private int thisColumn = -1;
// The last column printed to the output stream
private int lastColumnNumber = -1;
// Gathers characters as they are seen.
private StringBuffer value;
/**
* Accepts objects needed while parsing.
*
* #param styles Table of styles
* #param strings Table of shared strings
* #param cols Minimum number of columns to show
* #param target Sink for output
*/
public MyXSSFSheetHandler(
StylesTable styles,
ReadOnlySharedStringsTable strings,
int cols) {
this.stylesTable = styles;
this.sharedStringsTable = strings;
this.minColumnCount = cols;
this.value = new StringBuffer();
this.nextDataType = xssfDataType.NUMBER;
this.formatter = new DataFormatter();
}
/*
* (non-Javadoc)
* #see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if ("inlineStr".equals(name) || "v".equals(name)) {
vIsOpen = true;
// Clear contents cache
value.setLength(0);
}
// c => cell
else if ("c".equals(name)) {
// Get the cell reference
String r = attributes.getValue("r");
int firstDigit = -1;
for (int c = 0; c < r.length(); ++c) {
if (Character.isDigit(r.charAt(c))) {
firstDigit = c;
break;
}
}
thisColumn = nameToColumn(r.substring(0, firstDigit));
// Set up defaults.
this.nextDataType = xssfDataType.NUMBER;
this.formatIndex = -1;
this.formatString = null;
String cellType = attributes.getValue("t");
String cellStyleStr = attributes.getValue("s");
if ("b".equals(cellType))
nextDataType = xssfDataType.BOOL;
else if ("e".equals(cellType))
nextDataType = xssfDataType.ERROR;
else if ("inlineStr".equals(cellType))
nextDataType = xssfDataType.INLINESTR;
else if ("s".equals(cellType))
nextDataType = xssfDataType.SSTINDEX;
else if ("str".equals(cellType))
nextDataType = xssfDataType.FORMULA;
else if (cellStyleStr != null) {
// It's a number, but almost certainly one with a special style or format
int styleIndex = Integer.parseInt(cellStyleStr);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
this.formatIndex = style.getDataFormat();
this.formatString = style.getDataFormatString();
if (this.formatString == null)
this.formatString = BuiltinFormats.getBuiltinFormat(this.formatIndex);
}
}
}
StringBuffer columnvalue = new StringBuffer();
/*
* (non-Javadoc)
* #see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
public void endElement(String uri, String localName, String name)
throws SAXException {
String thisStr = null;
// v => contents of a cell
if ("v".equals(name)) {
// Process the value contents as required.
// Do now, as characters() may be called more than once
switch (nextDataType) {
case BOOL:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "\"ERROR:" + value.toString() + '"';
break;
case FORMULA:
// A formula could result in a string value, so always add double-quote characters.
thisStr = '"' + value.toString() + '"';
break;
case INLINESTR:
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
thisStr = '"' + rtsi.toString() + '"';
break;
case SSTINDEX:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
XSSFRichTextString rtss = new XSSFRichTextString(sharedStringsTable.getEntryAt(idx));
thisStr = '"' + rtss.toString() + '"';
}
catch (NumberFormatException ex) {
log.error("Failed to parse SST index '" + sstIndex + "': " + ex.toString());
throw new SAXException("Failed to parse SST index '" + sstIndex + "': " + ex.toString());
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null)
thisStr = formatter.formatRawCellContents(Double.parseDouble(n), this.formatIndex, this.formatString);
else
thisStr = n;
break;
default:
thisStr = "(TODO: Unexpected type: " + nextDataType + ")";
break;
}
// Output after we've seen the string contents
// Emit commas for any fields that were missing on this row
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
for (int i = lastColumnNumber; i < thisColumn; ++i){
//output.print(',');
columnvalue.append(",");
}
// Might be an empty string.
columnvalue.append(thisStr);
// Update column
if (thisColumn > -1)
lastColumnNumber = thisColumn;
} else if ("row".equals(name)) {
// Print out any missing commas if needed
if (minColumns > 0) {
// Columns are 0 based
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
for (int i = lastColumnNumber; i < (this.minColumnCount); i++) {
//output.print(',');
columnvalue.append(",");
}
}
// We're onto a new row
if(!GenericValidator.isBlankOrNull(columnvalue.toString())){
String completeVal = columnvalue.toString().replaceAll("\"", "");
allColValList.add(completeVal);
}
columnvalue = new StringBuffer("");
lastColumnNumber = -1;
}
}
/**
* Captures characters only if a suitable element is open.
* Originally was just "v"; extended for inlineStr also.
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
if (vIsOpen)
value.append(ch, start, length);
}
/**
* Converts an Excel column name like "C" to a zero-based index.
*
* #param name
* #return Index corresponding to the specified name
*/
private int nameToColumn(String name) {
int column = -1;
for (int i = 0; i < name.length(); ++i) {
int c = name.charAt(i);
column = (column + 1) * 26 + c - 'A';
}
return column;
}
}
private OPCPackage xlsxPackage;
private int minColumns;
/**
*
* #param pkg The XLSX package to process
* #param output The PrintStream to output the CSV to
* #param minColumns The minimum number of columns to output, or -1 for no minimum
*/
public XSSFListenerUtil(OPCPackage pkg, int minCol, ArrayList<String> colList, BaseViewBean baseViewBean$Session) {
this.xlsxPackage = pkg;
this.minColumns = minCol;
XSSFListenerUtil.allColValList = colList;
XSSFListenerUtil.baseViewBean$Session = baseViewBean$Session;
}
/**
* Parses and shows the content of one sheet
* using the specified styles and shared-strings tables.
*
* #param styles
* #param strings
* #param sheetInputStream
*/
public void processSheet(
StylesTable styles,
ReadOnlySharedStringsTable strings,
InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {
InputSource sheetSource = new InputSource(sheetInputStream);
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxFactory.newSAXParser();
XMLReader sheetParser = saxParser.getXMLReader();
ContentHandler handler = new MyXSSFSheetHandler(styles, strings, this.minColumns);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
}
/**
* Initiates the processing of the XLS workbook file to CSV.
*
* #throws IOException
* #throws OpenXML4JException
* #throws ParserConfigurationException
* #throws SAXException
*/
public void process()
throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
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()) {
InputStream stream = iter.next();
processSheet(styles, strings, stream);
stream.close();
++index;
}
}
public static void parseAndRetrieveExcelDetails(String filePath, InvestmentDimDao investmentDao,
BaseViewBean baseViewBean$Session, ActionMessages errors, boolean invalidTemplateIdentifier) throws Exception{
int minColumns = -1;
invalidTemplate = invalidTemplateIdentifier;
ArrayList<String> initialList = new ArrayList<String>();
//OPCPackage pkg = OPCPackage.open(filePath, PackageAccess.READ);
OPCPackage pkg = OPCPackage.open(filePath);
XSSFListenerUtil xssfSheetProcessor = new XSSFListenerUtil(pkg, minColumns, initialList, baseViewBean$Session);
xssfSheetProcessor.process();
validateAndExtractExcelData();
log.info("Finished processing all records");
if(invalidTemplate){
errors.add("failure", new ActionMessage("secaccess.file.invaliddata"));
}else{
log.info("All records parsed successfully");
}
allColValList.clear();
allColValList = null;
pkg.close();
System.gc();
}
private static void validateAndExtractExcelData() throws NumberFormatException {
int rowCnt = 1;
int colCnt = 0;
ExcelListenerBean listenerBean;
ExcelListenerBean bean;
Map <String, ExcelListenerBean> excelRecords = new TreeMap<String, ExcelListenerBean>();
for(String colVal : allColValList) {
if(rowCnt==1 && !AppGlobalConstants.HardCodedValues.G_L_CALC_HEADER1.equals(colVal)) {
invalidTemplate = true;
}
if(rowCnt==2 && !AppGlobalConstants.HardCodedValues.G_L_CALC_HEADER2.equals(colVal) & !invalidTemplate) {
invalidTemplate = true;
}
if(rowCnt==3 && !AppGlobalConstants.HardCodedValues.G_L_CALC_HEADER3.equals(colVal) & !invalidTemplate) {
invalidTemplate = true;
}
if(rowCnt > 3 && !invalidTemplate) {
listenerBean = new ExcelListenerBean(AppGlobalConstants.HardCodedValues.SQL_TYPE);
String[] allValues = colVal.split(",");
for(String cellContents : allValues){
switch (colCnt) {
case 0:
if(GenericValidator.isBlankOrNull(cellContents)){
invalidTemplate = true;
}else{
listenerBean = new ExcelListenerBean(AppGlobalConstants.HardCodedValues.SQL_TYPE);
listenerBean.setId(rowCnt);
listenerBean.setShortName(cellContents);
}
break;
case 1:
if(GenericValidator.isBlankOrNull(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setFmrCusip(cellContents);
}
break;
case 2:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdShares(Double.valueOf(cellContents));
}
break;
case 3:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdPrice(Double.valueOf(cellContents));
}
break;
case 4:
if(GenericValidator.isBlankOrNull(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdBuySell(cellContents);
}
break;
case 5:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdCommRate(Double.valueOf(cellContents));
}
break;
case 6:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdCommission(Double.valueOf(cellContents));
}
break;
case 7:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdFees(Double.valueOf(cellContents));
}
break;
case 8:
if(GenericValidator.isBlankOrNull(cellContents.toString()) || !GenericValidator.isDouble(cellContents.toString())){
invalidTemplate = true;
break;
}else{
listenerBean.setIncorrectTrdNet(Double.valueOf(cellContents.toString()));
}
break;
case 9:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdShares(Double.valueOf(cellContents));
}
break;
case 10:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdPrice(Double.valueOf(cellContents));
}
break;
case 11:
if(GenericValidator.isBlankOrNull(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdBuySell(cellContents);
}
break;
case 12:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdCommRate(Double.valueOf(cellContents));
}
break;
case 13:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdCommission(Double.valueOf(cellContents));
}
break;
case 14:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdFees(Double.valueOf(cellContents));
}
break;
case 15:
if(GenericValidator.isBlankOrNull(cellContents) || !GenericValidator.isDouble(cellContents)){
invalidTemplate = true;
break;
}else{
listenerBean.setCorrectionTrdNet(Double.valueOf(cellContents));
}
break;
}
colCnt++;
}
bean = excelRecords.get(listenerBean.getShortName());
if (bean != null){
listenerBean.setAcctGainLossAmt(new BigDecimal(Double.valueOf(bean.getAcctGainLossAmt()) + listenerBean.getCorrectionTrdNet() + listenerBean.getIncorrectTrdNet()).toPlainString());
} else {
listenerBean.setAcctGainLossAmt(new BigDecimal(listenerBean.getCorrectionTrdNet() + listenerBean.getIncorrectTrdNet()).toPlainString());
}
excelRecords.put(listenerBean.getShortName(), listenerBean);
}
colCnt = 0;
rowCnt++;
}
baseViewBean$Session.setExcelRecLst(new ArrayList<ExcelListenerBean>(excelRecords.values()));
log.info("Number of records for update is "+excelRecords.size());
}
}
I was running into same problem but then I realize that my file name was TestData.xlsx and I was using TestData.csv

Categories