我需要读取一个 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,方法如下:如何使用文档
http://poi.apache.org/spreadsheet/how-to.html
Grails Controller :
//
//
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);
//
//
类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,请帮助我解决问题。
最佳答案
Shashank 您可以使用相同的解决方案。要跳过空单元格,您所要做的就是检查它正在解析的标签。 此代码将 xlsx 转换为带有标签的 xml
<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 << ""
您还可以通过将偏移参数传递给方法并跳过第一个偏移行数来跳过标签行。
希望有帮助。
关于excel - 读取 XLSX 文件并将数据存储在 Grails 中的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27890813/