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ファイルがあるとします。
「商品」シートを読み込んで、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>