我需要读取一个XLSX文件,该文件包含5张大约50K行,Grails中约为7MB。
我需要逐页阅读文件,并且需要将每一行存储到数据库表中。
但我正在
Java heap space. Stacktrace follows:
Message: Executing action [abx] of controller [abc.xyz.controller] caused exception: Runtime error executing action
Line | Method
->> 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
我曾尝试通过将“GRAILS_OPTS”设置为
来增加堆空间GRAILS_OPTS=-XX:MaxPermSize=128m -XX:PermSize=128m -Xms1024m -Xmx1024m -XX:-UseGCOverheadLimit
但根本没有工作。
我遇到了这个问题
How to read XLSX file of size >40MB但此处没有适当的实施方案。
我尝试使用SAX从XLSX文件中读取XML,方法是从如何使用doc
开始http://poi.apache.org/spreadsheet/how-to.html
Grails控制器:
//
//
OPCPackage pkg = OPCPackage.open(filename);
XSSFReader r = new XSSFReader( pkg );
SharedStringsTable sst = r.getSharedStringsTable();
XMLReader parser1 =
XMLReaderFactory.createXMLReader(
"org.apache.xerces.parsers.SAXParser"
);
ContentHandler handler = new SheetHandler(sst);
//
//
class SheetHandler.java
class SheetHandler extends DefaultHandler {
private SharedStringsTable sst;
private String lastContents;
private boolean nextIsString;
private List<String> rowData
private SheetHandler(SharedStringsTable sst) {
rowData = []
this.sst = sst;
}
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
// c => cell
if(name.equals("c")) {
// Print the cell reference
//System.out.print(attributes.getValue("r") + " - ");
// Figure out if the value is an index in the SST
String cellType = attributes.getValue("t");
if(cellType != null && cellType.equals("s")) {
nextIsString = true;
} else {
nextIsString = false;
}
}
// Clear contents cache
lastContents = "";
}
public void endElement(String uri, String localName, String name)
throws SAXException {
if(name == "row"){
println rowData
rowData = []
}
// Process the last contents as required.
// Do now, as characters() may be called more than once
if(nextIsString) {
int idx = Integer.parseInt(lastContents);
lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
nextIsString = false;
}
// v => contents of a cell
// Output after we've seen the string contents
if(name.equals("v")) {
rowData << lastContents
System.out.println(lastContents);
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
lastContents += new String(ch, start, length);
}
}
通过实现上述功能,我无法将“标签”与“xlsx文件行”区分开来。而且我也无法获得列的空值。
我无法正确使用XSSFReader,请帮我解决问题。
答案 0 :(得分:0)
<r> for row
<c> for cell
<v> for value
并格式化
<r><c t="s" r="A32" s="50"><v>value in the cell</v></c></r> if there is a value in the cell
<r><c t="s" r="A32" s="50"></c></r> if there is no value in the cell.
所以,如果有一行有8列而第3列和第5列没有值那么它将读取xml的顺序将是(只需在startElement和endElement方法中打印变量名)
r cvvc cvvc cc cvvc cc cvvc cvvc cvvc r
其中cvvc表示
<c><v></v></c>
因此,只需检查startElement方法和endElement方法是否具有连续的c作为名称,这意味着它具有空值,然后只需在rowData中插入空白
rowData << ""
您也可以通过将偏移参数传递给方法并跳过第一个偏移行数来跳过标签行。
希望它有所帮助。