问题:
使用HSSF.EventUserModel,如何读取具有工作簿和工作表保护的XLS文件的所有记录(包括CellRecords)?
创建输入电子表格(在Excel 2010中):
>创建新的空白工作簿.
>将A1的值设置为数字:50
>将A2的值设置为字符串:50
>将A3的值设置为公式:= 25 * 2
>评论(功能区) – >保护表 – >密码:pass1
>评论(功能区) – >保护工作簿 – >密码:pass1
>文件(功能区) – >另存为… – >保存类型:Excel 97-2003工作簿
迄今取得的进展:
>在Excel中没有密码的情况下打开XLS文件.因此,您不需要密码才能在POI中打开它.
>使用新的HSSFWorkbook(Stream fs)成功打开XLS文件.但是,我需要EventUserModel的效率用于我的实际电子表格.
>设置NPOI.HSSF.Record.Crypto.Biff8EncryptionKey.CurrentUserPassword =“pass1”;不工作.
> ProcessRecord()函数捕获一个PasswordRecord,但我找不到有关如何正确处理它的任何文档.
>也许,EncryptionInfo或Decryptor类可能有一些用处.
注意:
我正在使用NPOI.但是,我可以将任何Java示例翻译为C#.
码:
我使用以下代码捕获Record事件. My Book1-unprotected.xls(无保护)显示所有Record事件(包括单元格值). My Book1-protected.xls显示一些记录并引发异常.
我只是在调试器中查看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(); } } }
更新(胡安梅拉多):
以下是例外.我现在最好的猜测(在Victor Petrykin的回答中)是HSSFEventFactory使用RecordInputStream,它无法本机解密受保护的记录.在收到异常后,processedRecords包含22条记录,包括以下可能重要的记录:
> processedRecords [5]是一个WriteAccessRecord,带有.name的乱码(可能是加密的)值
> 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,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)
解决方法
这段代码也有效,但它不是一个事件逻辑:
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);