3

我正在开发一个从 excel 文件 (xlsx) 读取数据的 Web 应用程序。我正在使用 POI 阅读 excel 表。问题是当我尝试读取 excel 文件时,服务器会抛出以下错误:

在此处输入图像描述

我尝试读取的 excel 文件大小接近 80 MB。这个问题有什么解决办法吗?

实际上,用户在将文件保存到磁盘后正在上传文件和应用程序尝试读取文件。我用于测试的代码片段是:

 File savedFile = new File(file_path);

FileInputStream fis = null;
            try {

                fis = new FileInputStream(savedFile);
                XSSFWorkbook xWorkbook = new XSSFWorkbook(fis);
                XSSFSheet xSheet = xWorkbook.getSheetAt(5);

                Iterator rows = xSheet.rowIterator();
                while (rows.hasNext()) {
                    XSSFRow row = (XSSFRow) rows.next();
                    Iterator cells = row.cellIterator();

                    List data = new ArrayList();
                    while (cells.hasNext()) {
                        XSSFCell cell = (XSSFCell) cells.next();
                        System.out.println(cell.getStringCellValue());
                        data.add(cell);
                    }

                }
            } catch (IOException e) {
                e.printStackTrace();
            } 
4

7 回答 7

3

有一点会有所不同的是,在打开文件开始时。如果你有一个文件,那就把它传进去!使用 InputStream 需要将所有内容缓冲到内存中,这会占用空间。由于您不需要进行缓冲,因此不要!

如果您使用 POI 的最新夜间版本运行,那么这非常容易。您的代码变为:

File file = new File(file_path);
OPCPackage opcPackage = OPCPackage.open(file);
XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);

否则,它非常相似:

File file = new File(file_path);
OPCPackage opcPackage = OPCPackage.open(file.getAbsolutePath());
XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);

这会释放你一些内存,这可能就足够了。如果不是这样,并且您无法将 Java 堆空间增加到足以应付的程度,那么您将不得不停止使用 XSSF UserModel。

除了您一直在使用的当前友好的 UserModel 之外,POI 还支持较低级别的文件处理方式。这种较低级别的方法更难使用,因为您周围没有各种需要将整个文件存储在内存中的助手。但是,当您以流式方式处理文件时,它的内存效率要高得多。要开始使用,请参阅POI 网站上的XSSF 和 SAX(事件 API)操作方法部分。尝试一下,并查看各种示例。

于 2012-06-20T23:52:50.077 回答
2

您可能应该更改 JVM 的设置。尝试添加-Xmx1024 -Xms1024到启动器。

于 2012-06-20T11:43:29.863 回答
1

您可以尝试增加您的 Java 堆大小。

于 2012-06-20T11:43:15.403 回答
1

我认为你必须增加堆的大小。您可以通过编辑 catalina.bat 文件来完成。添加-Xms1024m -Xmx1024mCATALINA_OPTS变量中。

  • Xms = 初始 Java 堆大小
  • Xmx = 最大 Java 堆大小

编辑:来自 Catalina.bat


rem   CATALINA_OPTS   (Optional) Java runtime options used when the "start",
rem                   "run" or "debug" command is executed.
rem                   Include here and not in JAVA_OPTS all options, that should
rem                   only be used by Tomcat itself, not by the stop process,
rem                   the version command etc.
rem                   Examples are heap size, GC logging, JMX ports etc.

于 2012-06-20T11:44:01.987 回答
0

对您当前方法的改进可能是从 excel中读取大约 100 行(用这个数字进行实验以获得最佳值)并在数据库中进行批量更新。这会更快。

您还可以在代码中执行一些优化,将列表创建移出外循环(用于读取行数据的循环)

列表数据 = new ArrayList();

读取字符串缓冲区中一行中存在的所有单元格的内容(可能用“逗号”分隔),然后将其添加到数组列表“数据”

您正在向XSSFRowarraylist 添加一个类型的对象。存储excel单元格的整个对象是没有意义的。取出其内容并丢弃该对象。

稍后在将内容插入数据库之前,您可以拆分分隔的单元格内容并执行插入。

希望这可以帮助!

于 2013-10-29T21:17:45.710 回答
0

我已经通过改变实施解决了这个问题。实际上,首先我从 Excel 文件中获取所有数据,并且数据存储在 ArrayList 类型中。之后我将数据插入数据库,这才是真正的问题。现在我根本不存储数据。当我从 ResultSet 中获得一条记录时,我立即将其插入 DB,而不是将其存储到 arraylist 中。我知道这个一个一个的插入不是一个好方法,但我暂时正在使用这种方法。将来如果我找到更好的,我肯定会切换到那个。谢谢大家。

于 2012-06-22T14:23:03.553 回答
-1

您最好将它们存储在文件中,然后尝试将它们加载到数据库中。这将避免单插入一个

于 2013-09-25T10:42:48.290 回答