通过HSSF.EventUserModel通过受保护的书籍和工作表读取XLS

END GOAL:有效地(一次通过)读取一个巨大的(30,000+行)受保护的Worksheet上的所有CellRecords

问题:使用HSSF.EventUserModel ,如何读取具有Workbook和Worksheet保护的XLS文件的所有Record (包括CellRecords )?

创buildinput电子表格(在Excel 2010中):

  1. 创build新的空白工作簿。
  2. 将A1的值设置为50
  3. 将A2的值设置为string:50
  4. 将A3的值设置为公式:= 25 * 2
  5. 审查(色带) – >保护表 – >密码:pass1
  6. 审查(function区) – >保护工作簿 – >密码:pass1
  7. 文件(function区) – >另存为… – >另存为types:Excel 97-2003工作簿

迄今取得的进展:

  • 在Excel中,XLS文件不用密码即可打开。 因此,您不应该需要密码才能在POI中打开它。
  • 使用new HSSFWorkbook(Stream fs)成功打开XLS文件。 但是,我需要为我的实际电子表格的EventUserModel效率。
  • 设置NPOI.HSSF.Record.Crypto.Biff8EncryptionKey.CurrentUserPassword = "pass1"; 不工作。
  • ProcessRecord( )函数捕获一个PasswordRecord ,但我找不到任何有关如何正确处理它的文档。
  • 也许, EncryptionInfoDecryptor类可能有一些用处。

注意:
我正在使用NPOI。 不过,我可以将任何Java示例翻译为C#。

码:
我使用下面的代码来捕获Record事件。 我的Book1-unprotected.xls (没有保护)显示所有Record事件(包括单元值)。 我的Book1-protected.xls显示一些logging并引发exception。

我只是在debugging器中查看processedEvents

 using System; using System.Collections.Generic; using System.IO; using NPOI.HSSF.Record; using NPOI.HSSF.Model; using NPOI.HSSF.UserModel; using NPOI.HSSF.EventUserModel; using NPOI.POIFS; using NPOI.POIFS.FileSystem; namespace NPOI_small { class myListener : IHSSFListener { List<Record> processedRecords; private Stream fs; public myListener(Stream fs) { processedRecords = new List<Record>(); this.fs = fs; HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); MissingRecordAwareHSSFListener mraListener; FormatTrackingHSSFListener fmtListener; EventWorkbookBuilder.SheetRecordCollectingListener recListener; mraListener = new MissingRecordAwareHSSFListener(this); fmtListener = new FormatTrackingHSSFListener(mraListener); recListener = new EventWorkbookBuilder.SheetRecordCollectingListener(fmtListener); request.AddListenerForAllRecords(recListener); POIFSFileSystem poifs = new POIFSFileSystem(this.fs); factory.ProcessWorkbookEvents(request, poifs); } public void ProcessRecord(Record record) { processedRecords.Add(record); } } class Program { static void Main(string[] args) { Stream fs = File.OpenRead(@"c:\users\me\desktop\xx\Book1-protected.xls"); myListener testListener = new myListener(fs); // Use EventModel //HSSFWorkbook book = new HSSFWorkbook(fs); // Use UserModel Console.Read(); } } } 

更新 (Juan Mellado) 下面是例外。 我现在最好的猜测(在Victor Petrykin的回答中)是HSSFEventFactory使用RecordInputStream ,它本身不能解密受保护的logging。 收到exception时, processedRecords包含22个logging,包括以下潜在的重要logging:

  • processedRecords [5]是一个WriteAccessRecord ,为.name带有乱码(可能是encryption的)
  • processedRecords [22]是一个RefreshAllRecord并且是列表中的最后一个Record

例外:

 NPOI.Util.RecordFormatException was unhandled HResult=-2146233088 Message=Unable to construct record instance Source=NPOI StackTrace: at NPOI.HSSF.Record.RecordFactory.ReflectionConstructorRecordCreator.Create(RecordInputStream in1) at NPOI.HSSF.Record.RecordFactory.CreateSingleRecord(RecordInputStream in1) at NPOI.HSSF.Record.RecordFactory.CreateRecord(RecordInputStream in1) at NPOI.HSSF.EventUserModel.HSSFRecordStream.GetNextRecord() at NPOI.HSSF.EventUserModel.HSSFRecordStream.NextRecord() at NPOI.HSSF.EventUserModel.HSSFEventFactory.GenericProcessEvents(HSSFRequest req, RecordInputStream in1) at NPOI.HSSF.EventUserModel.HSSFEventFactory.ProcessEvents(HSSFRequest req, Stream in1) at NPOI.HSSF.EventUserModel.HSSFEventFactory.ProcessWorkbookEvents(HSSFRequest req, POIFSFileSystem fs) at NPOI_small.myListener..ctor(Stream fs) in c:\Users\me\Documents\Visual Studio 2012\Projects\myTest\NPOI_small\Program.cs:line 35 at NPOI_small.Program.Main(String[] args) in c:\Users\me\Documents\Visual Studio 2012\Projects\myTest\NPOI_small\Program.cs:line 80 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: NPOI.Util.RecordFormatException HResult=-2146233088 Message=Expected to find a ContinueRecord in order to read remaining 137 of 144 chars Source=NPOI StackTrace: at NPOI.HSSF.Record.RecordInputStream.ReadStringCommon(Int32 requestedLength, Boolean pIsCompressedEncoding) at NPOI.HSSF.Record.RecordInputStream.ReadUnicodeLEString(Int32 requestedLength) at NPOI.HSSF.Record.FontRecord..ctor(RecordInputStream in1) 

我认为这是NPOI库代码中的错误。 据我了解,他们使用不正确的streamtypes为HSSFEventFactory :它使用RecordInputStream而不是RecordFactoryInputStream与解密函数像原始POI库或UserModel (这就是为什么HSSFWorkbook正在工作)

这个代码也在工作,但它不是一个事件逻辑:

 POIFSFileSystem poifs = new POIFSFileSystem(fs); Entry document = poifs.Root.GetEntry("Workbook"); DocumentInputStream docStream = new DocumentInputStream((DocumentEntry)document); //RecordFactory factory = new RecordFactory(); //List<Record> records = RecordFactory.CreateRecords(docStream); RecordFactoryInputStream recFacStream = new RecordFactoryInputStream(docStream, true); Record currRecord; while ((currRecord = recFacStream.NextRecord()) != null) ProcessRecord(currRecord);