我想读密码保护的Excel文件(.xls和.xlsx)格式与Apache POI。 我不使用的usermodel(org.apache.poi.ss.usermodel),但事件的API来处理XLS和XLSX档案(解决内存占用的问题)。
我采取HSSFListener并重写其processRecord(录音记录)方法的XLS文件。 对于XLSX文件,我使用javax.xml.parsers.SAXParser中和org.xml.sax.XMLReader中。
如果我使用下面的代码来读取.xls文件:
Biff8EncryptionKey.setCurrentUserPassword("password");
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(this.getFileName()));
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
formatListener = new FormatTrackingHSSFListener(listener);
HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
request.addListenerForAllRecords(formatListener);
rowsReadSet.clear();
factory.processWorkbookEvents(request, fs);
我得到这个异常:
Exception in thread "Thread-6" org.apache.poi.EncryptedDocumentException: HSSF does not currently support CryptoAPI encryption
at org.apache.poi.hssf.record.FilePassRecord$Rc4KeyData.read(FilePassRecord.java:65)
at org.apache.poi.hssf.record.FilePassRecord.<init>(FilePassRecord.java:193)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.apache.poi.hssf.record.RecordFactory$ReflectionConstructorRecordCreator.create(RecordFactory.java:87)
at org.apache.poi.hssf.record.RecordFactory.createSingleRecord(RecordFactory.java:338)
at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.<init>(RecordFactoryInputStream.java:74)
at org.apache.poi.hssf.record.RecordFactoryInputStream.<init>(RecordFactoryInputStream.java:207)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.genericProcessEvents(HSSFEventFactory.java:136)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processEvents(HSSFEventFactory.java:103)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:62)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:50)
at com.mycompany.component.reader.MSExcelReader.readxls(MSExcelReader.java:300)
at com.mycompany.component.reader.MSExcelReader.run(MSExcelReader.java:274)
at java.lang.Thread.run(Unknown Source)
一旦我得到的地方阅读的.xls我将张贴的.xlsx代码后。
我使用JDK7与Apache POI 3.11。 是否有人可以帮助?
[EDITED]
另一个问题是,我读到这里是
POI将无法读取加密的工作簿-这意味着,如果你保护了整个工作簿(而不仅仅是表),那么它将无法读取它。 否则,它应该工作。
这是真的? 因此,与POI 3.11,我无法阅读密码保护的文件,其中的密码设置为整个工作簿( - >工具 - >常规选项通常这是由另存为完成)?
[EDITED]:
如果我设置的片材的密码(采用回顾 - >保护工作表功能区选项),并利用事件模型读取该文件,它工作正常。 不过,如果我设置的密码为整个工作簿失败(使用评论 - >保护工作簿功能区选项)或文件设置密码(使用另存为 - >工具 - >常规选项)。 下面是我得到了这两个办法的例外情况:
1.使用回顾- >保护工作簿丝带选项
Exception in thread "Thread-6" org.apache.poi.EncryptedDocumentException: Supplied password is invalid for salt/verifier/verifierHash
at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.createDecryptingStream(RecordFactoryInputStream.java:127)
at org.apache.poi.hssf.record.RecordFactoryInputStream.<init>(RecordFactoryInputStream.java:209)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.genericProcessEvents(HSSFEventFactory.java:136)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processEvents(HSSFEventFactory.java:103)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:62)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:50)
我可以通过提供Decryptor.DEFAULT_PASSWORD或“VelvetSweatshop”字符串作为密码(这是一个默认的)读取这个文件。 那么,为什么它不能与手动设置的密码串读?
2.使用另存为- >工具- >常规选项
Exception in thread "Thread-6" org.apache.poi.EncryptedDocumentException: HSSF does not currently support CryptoAPI encryption
at org.apache.poi.hssf.record.FilePassRecord$Rc4KeyData.read(FilePassRecord.java:65)
at org.apache.poi.hssf.record.FilePassRecord.<init>(FilePassRecord.java:193)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.apache.poi.hssf.record.RecordFactory$ReflectionConstructorRecordCreator.create(RecordFactory.java:87)
at org.apache.poi.hssf.record.RecordFactory.createSingleRecord(RecordFactory.java:338)
at org.apache.poi.hssf.record.RecordFactoryInputStream$StreamEncryptionInfo.<init>(RecordFactoryInputStream.java:74)
at org.apache.poi.hssf.record.RecordFactoryInputStream.<init>(RecordFactoryInputStream.java:207)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.genericProcessEvents(HSSFEventFactory.java:136)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processEvents(HSSFEventFactory.java:103)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:62)
at org.apache.poi.hssf.eventusermodel.HSSFEventFactory.processWorkbookEvents(HSSFEventFactory.java:50)
我使用相同的密码所有上述三种方法,并使用MS Office专业增强版2013年为什么没有它的工作使用上述第一种方法(使用评论 - >保护工作簿)。 我收到的密码是在异常不正确。 使用第二种方法例外明确规定HSSF不支持加密,这样就可以了。 但我相信它应该工作,如果工作簿也受到保护(使用评论 - >保护工作簿),如果它可以读取用密码表(这是使用审查设定 - >保护工作表)。 专家可以澄清吗?
[EDITED]
好吧,我错了,当我说,它与的usermodel。 用上述两种方法(在编辑区段之前列出),它不与任一的usermodel工作。 我得到相同的异常与方法1.使用评论 - >保护工作簿色带的选择和方法2.使用另存为 - >工具 - >常规选项。 而设置为这片密码我可以读取该文件(类似的观察可以看到甚至模型太)。 请参阅样本测试用例下方。 我没有找到一个选项附加excel文件,所以不能做到这一点,但任何简单的Excel文件可以用下面的测试用例(尽管测试条件将根据输入的变化)进行测试。
简单的测试用例与用户模型和事件模型:
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
/**
* Testing for {@link HSSFEventFactory}
*/
public final class TestHSSFEventFactory extends TestCase {
private String[] fileNames = {"C:\\XLS\\General_Password.xls",
"C:\\XLS\\Sheet_Password.xls",
"C:\\XLS\\Workbook_Password.xls"};
private static class MockHSSFListener implements HSSFListener {
private final List<Record> records = new ArrayList<Record>();
public MockHSSFListener() {}
public Record[] getRecords() {
Record[] result = new Record[records.size()];
records.toArray(result);
return result;
}
public void processRecord(Record record) {
records.add(record);
}
}
public void testWithPasswordProtectedWorkbooksUserModel() throws Exception {
// XOR/RC4 decryption for xls
Biff8EncryptionKey.setCurrentUserPassword("4Sys-Tem");
NPOIFSFileSystem nfs = new NPOIFSFileSystem(new File(fileNames[2]), true);
HSSFWorkbook hwb = new HSSFWorkbook(nfs.getRoot(), true);
HSSFSheet sheet = hwb.getSheetAt(0);
HSSFRow row = sheet.getRow(2);
Cell cell1 = row.getCell(3);
row = sheet.getRow(3);
Cell cell2 = row.getCell(3);
row = sheet.getRow(4);
Cell cell3 = row.getCell(3);
assertEquals("17000.0", cell1.toString());
assertEquals("7500.0", cell2.toString());
assertEquals("5000.0", cell3.toString());
Biff8EncryptionKey.setCurrentUserPassword(null);
}
public void testWithPasswordProtectedWorkbooksEvenModel() throws Exception {
// With the password, is properly processed
Biff8EncryptionKey.setCurrentUserPassword("4Sys-Tem");
HSSFRequest req = new HSSFRequest();
MockHSSFListener mockListen = new MockHSSFListener();
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(fileNames[2]));
HSSFEventFactory factory = new HSSFEventFactory();
req.addListenerForAllRecords(mockListen);
factory.processWorkbookEvents(req, fs);
// Check we got the sheet and the contents
Record[] recs = mockListen.getRecords();
assertTrue( recs.length > 50 );
// Has one sheet, with values 1,2,3 in column A rows 1-3
boolean hasSheet=false, hasA1=false, hasA2=false, hasA3=false;
for (Record r : recs) {
if (r instanceof BoundSheetRecord) {
BoundSheetRecord bsr = (BoundSheetRecord)r;
assertEquals("Trade Data", bsr.getSheetname());
hasSheet = true;
}
if (r instanceof NumberRecord) {
NumberRecord nr = (NumberRecord)r;
if (nr.getColumn() == 3 && nr.getRow() == 2) {
assertEquals(17000, (int)nr.getValue());
hasA1 = true;
}
if (nr.getColumn() == 3 && nr.getRow() == 3) {
assertEquals(7500, (int)nr.getValue());
hasA2 = true;
}
if (nr.getColumn() == 3 && nr.getRow() == 4) {
assertEquals(5000, (int)nr.getValue());
hasA3 = true;
}
}
}
assertTrue("Sheet record not found", hasSheet);
assertTrue("Numeric record for A1 not found", hasA1);
assertTrue("Numeric record for A2 not found", hasA2);
assertTrue("Numeric record for A3 not found", hasA3);
}
}