FINE OBIETTIVO: efficiente (in un solo passaggio) Leggi tutte le CellRecords
su un enorme (30.000 fila), protetto Worksheet
.
Leggi XLS con protetta Libro e Foglio via HSSF.EventUserModel
Problema: Utilizzando il HSSF.EventUserModel
, come posso leggere tutti Record
s (tra cui CellRecords
) per un file XLS sia con cartella di lavoro e la protezione del foglio di lavoro?
Crea foglio di calcolo di ingresso (in Excel 2010):
- Crea nuova cartella di lavoro vuoto.
- valore Set di A1 al numero di: 50
- valore Set di A2 a stringa: cinquanta
- valore Set di A3 la formula: = 25 * 2
- Review (ribbon) -> Proteggi foglio -> Password : pass1
- Review (ribbon) -> Proteggi cartella di lavoro -> password: pass1
- file (nastro) -> Salva con nome ... -> Salva come: Excel 97-2003
Progress Finora:
- Il file XLS si apre senza una password in Excel. Pertanto, non dovresti aver bisogno della password per aprirla nel POI.
- Il file XLS si apre correttamente con
new HSSFWorkbook(Stream fs)
. Tuttavia, ho bisogno dell'efficienza diEventUserModel
per il mio foglio di calcolo effettivo. - L'impostazione
NPOI.HSSF.Record.Crypto.Biff8EncryptionKey.CurrentUserPassword = "pass1";
non ha funzionato. - La funzione
ProcessRecord()
rileva unoPasswordRecord
, ma non riesco a trovare alcuna documentazione su come gestirlo correttamente. - Forse le classi
EncryptionInfo
oDecryptor
possono essere di qualche utilità.
Nota:
Sto utilizzando NPOI. Tuttavia, posso tradurre qualsiasi esempio java in C#.
Codice:
Io uso il seguente codice per acquisire Record
eventi. Il mio Book1-unprotected.xls
(senza protezione) mostra tutti gli eventi Record
(compresi i valori delle celle). Il mio Book1-protected.xls
visualizza alcuni record e genera un'eccezione.
Ho appena visualizzato processedEvents
nel debugger.
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();
}
}
}
UPDATE (per Juan Mellado) : Sotto è l'eccezione. La mia ipotesi migliore ora (nella risposta di Victor Petrykin) è che lo HSSFEventFactory
utilizza RecordInputStream
che non può decifrare in modo nativo i record protetti.Alla ricezione eccezione, processedRecords
contiene 22 records compresi i seguenti potenzialmente significative:
- processedRecords [5] è un
WriteAccessRecord
con un valore alterata (probabilmente criptato) per.name
- processedRecords [22] è una
RefreshAllRecord
e è l'ultimoRecord
nella lista
Eccezione:
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)
Ho testato una versione equivalente Java del codice e funziona come previsto. Voglio dire, non è necessario specificare alcuna password per leggere le celle protette. Il metodo di callback 'processRecord' riceve tutti gli oggetti' CellRecord', come 'NumberRecord' o' FormulaRecord', in modo che io possa rilevarli e accedere ai loro attributi (Ex: '((Record di NumberRecord)) .getValue()'). Un oggetto 'ProtectRecord' ha solo un attributo flag per dire se il record corrente è protetto. Puoi aggiungere qualche informazione in più su cosa significa "come gestirlo correttamente"? E, ovviamente, la traccia dello stack dell'eccezione che hai ottenuto. –
@JuanMellado: vedere l'aggiornamento del post principale per i dettagli. – Steven