daybreaksnow's diary

私を私と呼びたい

[Java]Apache POI でパスワードがかかったExcelを読み込んだ際に発生する例外

Apache POI 3.6-20091214
パスワードがかかっているExcelファイルを読み込んだ際に発生する例外

拡張子 読込パスワード 書込パスワード 例外クラス
xls RecordFormatException
xls EncryptedDocumentException
xls 例外は発生せず読み込み可能
xlsx InvalidOperationException
xlsx InvalidOperationException
xlsx 例外は発生せず読み込み可能


ワークブック作成時に上記例外が発生したらパスワードがかかっているとみなすようにしたが、EncryptedDocumentException以外については誤検出がありそう。妥当な対応はないのだろうか。

サンプルコード

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


public class ExcelImportTest {
	public static void main(String[] args) throws FileNotFoundException, IOException {
		File folder = new File("./resource/");
		File[] list = folder.listFiles();
		for (File file : list) {
			String suffix = getSuffix(file);
			System.err.println("\n" + file.getName());
			Workbook workbook ;
			try{
				workbook = openWorkbook(file, suffix);
			}catch(Exception e){
				e.printStackTrace();
				continue;
			}
			String value = workbook.getSheetAt(0).getRow(0).getCell(0).getStringCellValue();
			System.err.println("value:" + value);
		}
	}

	private static Workbook openWorkbook(File file, String suffix) throws IOException, FileNotFoundException {
		if("xls".equals(suffix)){
			return new HSSFWorkbook(new FileInputStream(file));
		}
		else if("xlsx".equals(suffix)){
			return new XSSFWorkbook(new FileInputStream(file));
		}
		return null;
	}

	private static String getSuffix(File path) {
		if (path.isDirectory()) {
	        return null;
	    }

	    String fileName = path.getName();

	    int lastDotPosition = fileName.lastIndexOf(".");
	    if (lastDotPosition != -1) {
	        return fileName.substring(lastDotPosition + 1);
	    }
	    return null;
	}
}

実行結果

nopass.xls
value:hogege

nopass.xlsx
value:hogege

readpass_hoge.xls
org.apache.poi.EncryptedDocumentException: Default password is invalid for docId/saltData/saltHash
	at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.createDecryptingStream(RecordFactoryInputStream.java:101)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.(RecordFactoryInputStream.java:169)
	at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:389)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:276)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:201)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:317)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:298)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:32)
	at ExcelImportTest.main(ExcelImportTest.java:20)

readpass_hoge.xlsx
org.apache.poi.openxml4j.exceptions.InvalidOperationException: Can't open the specified file: 'C:\Users\USER1~1.DEV\AppData\Local\Temp\poifiles\poi-ooxml-1994526719.tmp'
	at org.apache.poi.openxml4j.opc.ZipPackage.(ZipPackage.java:102)
	at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:199)
	at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:178)
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:53)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:176)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:35)
	at ExcelImportTest.main(ExcelImportTest.java:20)

readwritepass_hoge.xls
org.apache.poi.hssf.record.RecordFormatException: Unable to construct record instance
	at org.apache.poi.hssf.record.RecordFactory$ReflectionRecordCreator.create(RecordFactory.java:64)
	at org.apache.poi.hssf.record.RecordFactory.createSingleRecord(RecordFactory.java:263)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.readNextRecord(RecordFactoryInputStream.java:270)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.nextRecord(RecordFactoryInputStream.java:236)
	at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:392)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:276)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:201)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:317)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:298)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:32)
	at ExcelImportTest.main(ExcelImportTest.java:20)
Caused by: java.lang.IllegalArgumentException: Name is too long: ???PZ???)???S??K?j??x????E1?qe/6???n????d

なお、最新のPOI(poi-3.9-20121203)では以下の通り

拡張子 読込パスワード 書込パスワード 例外クラス
xls EncryptedDocumentException
xls EncryptedDocumentException
xls 例外は発生せず読み込み可能
xlsx POIXMLException
xlsx POIXMLException
xlsx 例外は発生せず読み込み可能

実行結果

nopass.xls
value:hogege

nopass.xlsx
value:hogege

readpass_hoge.xls
org.apache.poi.EncryptedDocumentException: Default password is invalid for docId/saltData/saltHash
	at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.createDecryptingStream(RecordFactoryInputStream.java:116)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.(RecordFactoryInputStream.java:184)
	at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:440)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:280)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:243)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:187)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:322)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:303)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:32)
	at ExcelImportTest.main(ExcelImportTest.java:20)

readpass_hoge.xlsx
org.apache.poi.POIXMLException: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:41)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:204)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:35)
	at ExcelImportTest.main(ExcelImportTest.java:20)
Caused by: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]
	at org.apache.poi.openxml4j.opc.ZipPackage.getPartsImpl(ZipPackage.java:178)
	at org.apache.poi.openxml4j.opc.OPCPackage.getParts(OPCPackage.java:662)
	at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:269)
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:39)
	... 3 more

readwritepass_hoge.xls
org.apache.poi.EncryptedDocumentException: Default password is invalid for docId/saltData/saltHash
	at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.createDecryptingStream(RecordFactoryInputStream.java:116)
	at org.apache.poi.hssf.record.RecordFactoryInputStream.(RecordFactoryInputStream.java:184)
	at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:440)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:280)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:243)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:187)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:322)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.(HSSFWorkbook.java:303)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:32)
	at ExcelImportTest.main(ExcelImportTest.java:20)

readwritepass_hoge.xlsx
org.apache.poi.POIXMLException: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:41)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:204)
	at ExcelImportTest.openWorkbook(ExcelImportTest.java:35)
	at ExcelImportTest.main(ExcelImportTest.java:20)
Caused by: org.apache.poi.openxml4j.exceptions.InvalidFormatException: Package should contain a content type part [M1.13]
	at org.apache.poi.openxml4j.opc.ZipPackage.getPartsImpl(ZipPackage.java:178)
	at org.apache.poi.openxml4j.opc.OPCPackage.getParts(OPCPackage.java:662)
	at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:269)
	at org.apache.poi.util.PackageHelper.open(PackageHelper.java:39)
	... 3 more

writepass_hoge.xls
value:hogege

writepass_hoge.xlsx
value:hogege