如何使用POI(与Eevnt模型)来读取密码保护的Excel文件?(How to read pass

2019-10-22 18:07发布

我想读密码保护的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);
    }
}   
文章来源: How to read password protected excel files using POI (with Eevnt model)?