LoginSignup
0
0

More than 1 year has passed since last update.

メモリ消費量を抑えてxlsxファイルを読み込みたい

Posted at

Apache POIを利用してxlsxファイルを読み込む方法として、インターネット上ではUser APIがよく紹介されています (HSSFWorkbookとかを利用するもの)。これは便利ですが、読み込む対象のxlsxファイルをすべてメモリ上に展開するので、巨大なxlsxファイルを読み込む場合は、大量のメモリを消費する場合があります。

ではメモリ消費量を抑えて、xlsxファイルを読み込みたい場合はどうすればよいかというと、Event APIというAPIを利用します。自分はこのAPIをよく利用するのですが、インターネット上に日本語情報が少なく、実装のたびに困っているので、自分用にまとめておこうと思います。ちなみに以下の記事も参考にしてください。

以下はEvent APIを利用し、対象のシートを読み込んで、2次元配列に変換するサンプルです。

public class SheetToMatrix {

    public List<List<String>> toMatrix(Path path, String sheetName) {
        try (OPCPackage opcPackage = OPCPackage.open(path.toFile(), PackageAccess.READ)) {
            XSSFReader xssfReader = new XSSFReader(opcPackage);
            SheetIterator sheetsData = (SheetIterator) xssfReader.getSheetsData();

            while (sheetsData.hasNext()) {
                try (InputStream inputStream = sheetsData.next()) {
                    if (!Objects.equals(sheetsData.getSheetName(), sheetName)) {
                        continue;
                    }

                    XMLReader sheetParser = XMLHelper.newXMLReader();
                    SheetToMatrixHandler sheetToMatrixHandler = new SheetToMatrixHandler();
                    ContentHandler contentHandler = new XSSFSheetXMLHandler(
                            xssfReader.getStylesTable(),
                            new ReadOnlySharedStringsTable(opcPackage),
                            sheetToMatrixHandler,
                            false);
                    sheetParser.setContentHandler(contentHandler);
                    sheetParser.parse(new InputSource(inputStream));
                    return sheetToMatrixHandler.getMatrix();
                }
            }

            throw new RuntimeException("対象のシートがありません: " + sheetName);
        } catch (InvalidOperationException
                | IOException
                | OpenXML4JException
                | SAXException
                | ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    public static class SheetToMatrixHandler implements SheetContentsHandler {

        private List<List<String>> matrix;

        public SheetToMatrixHandler() {
            matrix = new ArrayList<>();
        }

        public List<List<String>> getMatrix() {
            return matrix;
        }

        @Override
        public void cell(String cellReference, String formattedValue, XSSFComment comment) {
            CellReference cr = new CellReference(cellReference);
            int row = cr.getRow();
            int col = cr.getCol();

            while (matrix.size() <= row) {
                matrix.add(new ArrayList<>());
            }
            while (matrix.get(row).size() <= col) {
                matrix.get(row).add("");
            }

            matrix.get(row).set(col, formattedValue);
        }

        @Override
        public void startRow(int rowNum) {
            // PASS
        }

        @Override
        public void endRow(int rowNum) {
            // PASS
        }
    }
}

実際に利用してみましょう。たとえば以下のようなxlsxファイルがあるとします。
image.png

「商品」シートを読み込んで、2次元配列に変換し、内容をコンソールに出力してみましょう。

List<List<String>> matrix = new SheetToMatrix().toMatrix(Paths.get("商品.xlsx"), "商品");
System.out.println(matrix);

以下のような結果がコンソールに出力されるはずです。

[[りんご, 100, 1], [みかん, 200], [いちご, , 3], [], [すいか, 400, 4], [], [], [ばなな, 500, 5]]

環境情報

pom.xml
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>17</maven.compiler.source>
  <maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
  <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>5.2.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
  <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.2.3</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
  <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.19.0</version>
  </dependency>
</dependencies>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0