END cel: Skutecznie (w jednym przejściu) czytaj wszystkie CellRecords
na ogromnym (30.000 rzędzie), chroniony Worksheet
.
Czytaj XLS z zabezpieczonymi Książki i Karcie poprzez HSSF.EventUserModel
Problem: Używanie HSSF.EventUserModel
, w jaki sposób można odczytać wszystkie Record
s (w tym CellRecords
) do pliku XLS z obu skoroszytu i ochrony Arkusz?
Tworzenie arkusza kalkulacyjnego Excel wejścia (w 2010 roku):
- Utwórz nowy pusty skoroszyt.
- wartość Zestaw A1 na numer: 50
- Ustawiona wartość A2 ciąg: pięćdziesiąt
- ustawionej wartości A3 do wzoru: = 25 * 2
- Review (wstążka) -> Chroń arkusz -> Hasło : pass1
- Review (wstążka) -> Chroń skoroszyt -> Hasło: pass1
- plików (wstążka) -> Zapisz jako ... -> Zapisz jako typ: Excel 97-2003 skoroszyt
Progress do tej pory:
- Plik XLS otwiera się bez hasła w programie Excel. Dlatego nie trzeba hasła, aby otworzyć go w POI.
- Plik XLS otwiera się pomyślnie pod numerem
new HSSFWorkbook(Stream fs)
. Jednak potrzebuję wydajnościEventUserModel
dla mojego rzeczywistego arkusza kalkulacyjnego. - Ustawienie
NPOI.HSSF.Record.Crypto.Biff8EncryptionKey.CurrentUserPassword = "pass1";
nie działa. - Funkcja przechwytuje numer
PasswordRecord
, ale nie mogę znaleźć żadnej dokumentacji dotyczącej prawidłowego posługiwania się nim. - Być może niektóre klasy mogą mieć klasę
EncryptionInfo
lubDecryptor
.
Uwaga:
Używam NPOI. Mogę jednak przetłumaczyć dowolne przykłady języka Java na język C#.
Kod:
Poniższy kod służy do rejestrowania zdarzeń Record
. Mój Book1-unprotected.xls
(bez zabezpieczenia) pokazuje wszystkie zdarzenia (w tym wartości komórek). Mój Book1-protected.xls
wyświetla niektóre rekordy i zgłasza wyjątek.
Właśnie widzę processedEvents
w debugerze.
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 (Juan Mellado) : Poniżej jest wyjątkiem. Moje najlepsze przypuszczenie w tej chwili (w odpowiedzi Victora Petrykina) jest takie, że HSSFEventFactory
używa RecordInputStream
, która nie może natywnie odszyfrować chronionych rekordów.Po otrzymaniu wyjątek processedRecords
zawiera 22 rejestrów w tym następujących, potencjalnie istotne, takie:
- processedRecords [5] jest
WriteAccessRecord
z zniekształcone (prawdopodobnie zaszyfrowanych) wartości dla.name
- processedRecords [22] jest
RefreshAllRecord
i jest to ostatniaRecord
na liście
Wyjątek:
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)
Przetestowałem wersję kodu równoważną Java i działa ona zgodnie z oczekiwaniami. To znaczy, nie trzeba określać żadnego hasła do odczytu chronionych komórek. Metoda zwrotna 'processRecord' odbiera wszystkie obiekty' CellRecord', takie jak 'NumberRecord' lub' FormulaRecord', dzięki czemu mogłem je wykryć i uzyskać dostęp do ich atrybutów (Ex: '((NumberRecord)) .getValue()'). Obiekt 'ProtectRecord' ma atrybut flag, który określa, czy bieżący rekord jest chroniony. Czy możesz dodać więcej informacji o tym, co oznacza "jak prawidłowo sobie z tym poradzić"? I, oczywiście, ślad stosu wyjątku, jaki masz. –
@JuanMellado: Szczegółowe informacje można znaleźć w głównej aktualizacji posta. – Steven