[POI] テンプレートファイルが書き変わるようになってしまった

Apache POI

2015年11月9日現在の Apache POI の最新バージョンは 3.13 です。

エクセルやワードを生成する機能が含まれる新しいシステムを構築しています。
新規構築にあたり、Apache POI を最新化しつつ、エクセルの生成プログラムは古いシステムから流用することになりました。

しかし、同じように記述しているのにどうもおかしいのです。
コーディングで久々にハマりました。

何がおかしいかと言うと、保存していないつもりなのに、テンプレートにしているファイルが書き変わってしまうのです。
ByteArrayOutputStream に対して write しているのに! です。

いろいろ疑いました。 テンプレートの開き方が悪いのか、POIのバグか。
ネット上には古い記事が溢れているので、検索しても有益な情報は見つからず、原因は把握に時間を要してしまいました。
(Apache POIの記事がネット上に溢れすぎているので、そろそろ名前を変えてほしいです。)

英語に明るくない私は、ドキュメントは読まずにとにかく検証してみました。(ははっ
結果から言うと 3.10 から 3.11 になって、動作が変わったようです。

対応方法について「[POI] 対処編:テンプレートファイルが書き変わるようになってしまった」を見てください。

確認用のコードを以下に晒しておきます。
予め言い訳しておきますが、動作確認用なので手抜きコードです。
Java は 8 です。

package test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class TestThePoi {

	public static void main(final String[] args) throws EncryptedDocumentException, InvalidFormatException, IOException {
		try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
			try (final Workbook workbook = WorkbookFactory.create(new File("input.xlsx"))) {
				for (final Sheet sheet : workbook) {
					final Row row = sheet.createRow(sheet.getLastRowNum() + 1);
					row.createCell(0).setCellValue(new Date());
				}
				workbook.write(baos);
			}
			final File output = new File("output.xlsx");
			output.delete();
			output.createNewFile();
			try (FileOutputStream fos = new FileOutputStream(output)) {
				fos.write(baos.toByteArray());
			}
		}
	}
}

↑ テンプレートにしたファイルが書き変わる

package test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class TestThePoi {
	public static void main(final String[] args) throws EncryptedDocumentException, InvalidFormatException, IOException {
		try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
			try (XSSFWorkbook workbook = (XSSFWorkbook) WorkbookFactory.create(new File("input.xlsx"))) {
				for (final Sheet sheet : workbook) {
					final Row row = sheet.createRow(sheet.getLastRowNum() + 1);
					row.createCell(0).setCellValue(new Date());
				}
				workbook.write(baos);
			}
			final File output = new File("output.xlsx");
			output.delete();
			output.createNewFile();
			try (FileOutputStream fos = new FileOutputStream(output)) {
				fos.write(baos.toByteArray());
			}
		}
	}
}

↑ テンプレートにしたファイルが書き変わる

package test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class TestThePoi {
	public static void main(final String[] args) throws EncryptedDocumentException, InvalidFormatException, IOException {
		try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
			final Workbook workbook = WorkbookFactory.create(new File("input.xlsx"));
			for (int index = 0; index < workbook.getNumberOfSheets(); index++) {
				final Sheet sheet = workbook.getSheetAt(index);
				final Row row = sheet.createRow(sheet.getLastRowNum() + 1);
				row.createCell(0).setCellValue(new Date());
			}
			workbook.write(baos);

			final File output = new File("output.xlsx");
			output.delete();
			output.createNewFile();
			try (FileOutputStream fos = new FileOutputStream(output)) {
				fos.write(baos.toByteArray());
			}
		}
	}
}

↑ テンプレートにしたファイルは書き変わらない

コメント