读取XLSX文件并将数据存储在Grails中的有效方法

时间:2015-01-11 18:54:25

标签: excel grails groovy apache-poi sax

我需要读取一个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,请帮我解决问题。

1 个答案:

答案 0 :(得分:0)

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 << ""

您也可以通过将偏移参数传递给方法并跳过第一个偏移行数来跳过标签行。

希望它有所帮助。