如何使用POI读取和编辑大型Excel文件?

时间:2013-06-04 05:20:03

标签: apache-poi

我要求执行以下操作

1)复制一个巨大的Excel文件1400 * 1400并制作副本。

2)读取复制的文件并添加新的列和行,同时进行编辑。

3)这将是一个独立的程序,而不是在服务器上。我有内存占用少,性能快的局限性。

我做了一些阅读并找到了以下内容

1)没有API来复制一个巨大的文件

2)SXSSF可用于写作但不能用于阅读

3)XSSF和SAX(事件API)可用于阅读但不能用于编辑。如果我再次尝试读取和存储为对象,则会出现内存问题。

请帮助我如何做到这一点?

3 个答案:

答案 0 :(得分:1)

假设您的内存大小足以使用XSSF / SAX读取和SXSSF写入,请允许我建议以下解决方案。

1)使用XSSF / SAX读取文件。对于每一行,使用行数据创建一个对象,并使用ObjectOutputStream或您认为方便的任何其他输出格式立即将其写入文件。您将为每行创建单独的文件。并且内存中只有1个行对象,因为您可以继续使用每行的数据修改同一个对象。

2)进行所需的任何修改。对于需要修改的行,请将相应的文件读回行对象,根据需要进行修改,然后将其写回。对于新行,只需在行对象中设置数据并将其写入新文件即可。

3)使用SXSSF重新组合电子表格,方法是一次读取1行目标文件并将其存储在输出电子表格中。

这样,你一次只能在内存中占一行。

答案 1 :(得分:1)

如果有大量数据由于“超出内存”或“超出GC限制”而发生,并且内存有问题,则数据最初可以解析为xml文件。可以使用xml文件替换excel表,以便最小化内存使用量。

在excel中,工作表表示为xml。使用java.util.zip.ZipFile可以识别每个条目。工作表的xml可以用解析的xml替换,以便我们在Excel工作表中获得预期的数据。

以下类可用于创建xml文件:

public class XmlSpreadsheetWriter {
    private final Writer _out;
    private int _rownum;

    public XmlSpreadsheetWriter(Writer out){
        _out = out;
    }

    public void beginSheet() throws IOException {
        _out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" );
        _out.write("<sheetData>\n");
    }

    public void endSheet() throws IOException {
        _out.write("</sheetData>");
        _out.write("</worksheet>");
    }

    public void insertRow(int rownum) throws IOException {
        _out.write("<row r=\""+(rownum+1)+"\">\n");
        this._rownum = rownum;
    }

    public void endRow() throws IOException {
        _out.write("</row>\n");
    }

    public void createCell(int columnIndex, String value, int styleIndex) throws IOException {
     String ref = new CellReference(_rownum, columnIndex).formatAsString();
     _out.write("<c r=\""+ref+"\" t=\"inlineStr\"");
     _out.write(" s=\""+styleIndex+"\"");
     _out.write(">");
     _out.write("<is><t>"+value+"</t></is>");
     _out.write("</c>");
    }

    public void createCell(int columnIndex, double value, int styleIndex) throws IOException {
     String ref = new CellReference(_rownum, columnIndex).formatAsString();
     _out.write("<c r=\""+ref+"\" t=\"n\"");
     _out.write(" s=\""+styleIndex+"\"");
     _out.write(">");
     _out.write("<v>"+value+"</v>");
     _out.write("</c>");
    }

    public void createEmptyCell(int columnIndex, int styleIndex)throws IOException {
     String ref = new CellReference(_rownum, columnIndex).formatAsString();
     _out.write("<c r=\""+ref+"\" t=\"n\"");
     _out.write(" s=\""+styleIndex+"\"");
     _out.write(">");
     _out.write("<v></v>");
     _out.write("</c>");
    }
} 

答案 2 :(得分:0)

如果内存是处理您指出的记录数(即1400 * 1400)的问题,那么获取XML数据并处理这些数据可能是您的解决方案。我知道它可能不是最好的解决方案,但它肯定会满足您的低内存要求。甚至POI网站也指出了这个解决方案:

“如果内存占用是个问题,那么对于XSSF,您可以获取基础XML数据并自行处理。这适用于愿意学习.xlsx的一些低级结构的中间开发人员。文件,以及谁喜欢在java中处理XML。它使用相对简单,但需要对文件结构有基本的了解。提供的优点是你可以读取内存占用相对较小的XLSX文件。“

源:http://poi.apache.org/spreadsheet/how-to.html