Noen ganger er det eneste spørsmålet en mottaksrutine trenger svar på, strukturelt: har denne arbeidsboken et ark som heter "Mapping", eller hvor mange faner har den. Å svare på det ved å kalle Open er den kostbare måten å gjøre det på. En full åpning blåser opp den delte strengtabellen, dekoder hver eneste stilpost, og går gjennom cellene i hvert ark, fordi den ikke har noen måte å vite at du bare ville ha innholdsfortegnelsen. På en stor fil er det hundrevis av megabyte med allokeringer og flere sekunder med CPU-tid brukt på å lese en liste som opptar noen få kilobyte. HotXLS, det native Delphi-regnearkbiblioteket fra losLab, gir deg den listen på egen hånd: GetSheetNames gir tilbake arknavnene, i arbeidsbokens rekkefølge, uten å materialisere en eneste celle
Hvorfor katalogen er billig å lese
Begge regnearkformatene plasserer innholdsfortegnelsen sin nær begynnelsen, og det er det som gjør et listekall raskt fremfor smart. En OOXML-pakke holder arkkatalogen i xl/workbook.xml, en del som forblir liten enten arbeidsboken har ti rader eller ti millioner. En BIFF8 .xls lagrer sine BoundSheet-poster helt i starten av arbeidsbokens globale strøm, foran all celledata. Så arbeidet et listekall unngår, er ikke en avrundingsfeil mot en full åpning. Det er mesteparten av filen. Å lese katalogen koster de samme få kilobytene uansett antall rader, mens en full åpning skalerer med dataene, og på en arbeidsbok på flere megabyte løper det gapet opp i flere størrelsesordener, både i berørte byte og allokert minne
Den flate kostnaden er egenskapen det er verdt å designe rundt. En mottaksport bygget på GetSheetNames oppfører seg likt på en fil med 200 rader og en på 200 MB, slik at den tregeste filen i en batch ikke lenger setter tempoet for å avgjøre om en fil i det hele tatt er verdt å behandle
Ett kall på tvers av .xls, .xlsx og malformatene
På XLS-fasaden leser TXLSWorkbook.GetSheetNames mer enn bare .xls. Den godtar også de zip-baserte .xlsx, .xlsm, .xltx og .xltm, og henter bare workbook.xml ut av arkivet. For ekte .xls-inndata skanner den BoundSheet-poster og stopper ved den første EOF-posten i den globale delstrømmen, slik at en stor binærfil fortsatt bare koster de innledende kilobytene. XLSX-fasaden bærer en garanti som betyr mer for langtidskjørende tjenestekode enn det først virker: TXLSXWorkbook.GetSheetNames lar arbeidsbokinstansen verken tilbakestilles eller fylles, slik at en instans som allerede holder et åpent dokument, kan sondere andre filer uten å forstyrre den som allerede er i hånden. GetODSSheetNames bruker samme tilnærming på OpenDocument-pakker, og hvert eneste av disse kallene har en strømoverlasting, som lar deg inspisere en opplasting som aldri havner på disk
var
Book: TXLSXWorkbook;
Names: TStringList;
I: Integer;
begin
Names := TStringList.Create;
Book := TXLSXWorkbook.Create;
try
if Book.GetSheetNames('upload-7f3a.xlsx', Names) <= 0 then
raise Exception.Create('unreadable workbook package');
if Names.IndexOf('Mapping') < 0 then
raise Exception.Create('required Mapping sheet is missing');
for I := 0 to Names.Count - 1 do
Writeln(Format('sheet %d: %s', [I, Names[I]]));
finally
Book.Free;
Names.Free;
end;
end;
Det samme kallet gir en god importdialog for skrivebordet. List opp arkene, la brukeren velge ett, og betal for den fulle åpningen først etter at valget er gjort. Med en arbeidsbok på femti ark er forskjellen synlig: en velger som dukker opp momentant, mot en som stopper opp mens hele filen lastes bak den
Makroaktiverte .xlsm-filer og malformatene listes akkurat som en vanlig .xlsx, siden katalogen ligger i den samme workbook.xml uansett om en vbaProject.bin følger med i pakken eller ikke. En mottakspipeline kan derfor liste opp arkene til en makroarbeidsbok for ruting, uten noensinne å røre makronyttelasten eller gjøre noe som ville kjørt den, og overlate makropolicybeslutningen til trinnet som faktisk åpner filen
Å lese returverdien uten å lure seg selv
Returkonvensjonene er ikke ensartede på tvers av HotXLS. Noen kall returnerer 1 ved suksess, andre returnerer et antall, så for listefunksjonene er den eneste kontrollen som holder, å behandle enhver verdi på null eller lavere som en feil, med strenglisten tømt. Stå imot fristelsen til å lese en tom liste som "en arbeidsbok uten ark". Både ECMA-376 og BIFF8-spesifikasjonen krever minst ett ark i en gyldig arbeidsbok, så null navn betyr alltid at lesingen mislyktes, aldri at filen legitimt er tom
En mislykket listing er i seg selv et signal verdt å beholde. En .xlsx-fil som feiler ved kallet, er én av noen få spesifikke ting: avkuttet, egentlig ikke en OOXML-pakke i det hele tatt (feilmerkede CSV-eksporter fra andre systemer dukker konstant opp her), eller en kryptert beholder. Å skille disse fra hverandre er jobben til neste kontroll. Å logge de første bytene av den avviste filen sammen med feilen gjør som regel en supporttråd om til én enkelt melding
Å oppdage krypterte beholdere før du ruter
En kryptert .xlsx er ikke en zip. Det er en OLE-sammensatt fil som pakker inn EncryptionInfo- og EncryptedPackage-strømmer, så GetSheetNames kan ikke se inn i den og returnerer feil som enhver annen uleselig fil. CanReadEncrypted tester for nettopp den beholderformen, som lar mottaket rute en kryptert fil med hensikt, fremfor å svelge en generisk lesefeil et sted dypt inne i en arbeidsprosess:
type
TIntakeRoute = (irNormal, irNeedsPassword, irUnreadable);
function ClassifyUpload(const FileName: string; Names: TStrings): TIntakeRoute;
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// Kryptert OOXML er en OLE-beholder, ikke en zip: sjekk først,
// fordi listekallene ikke kan se inn i den.
if Book.CanReadEncrypted(FileName) then
Exit(irNeedsPassword);
if SameText(ExtractFileExt(FileName), '.ods') then
begin
if Book.GetODSSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
end
else if Book.GetSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
Result := irNormal;
finally
Book.Free;
end;
end;
Kryptering er der HotXLS er bevisst asymmetrisk, så rutingen må respektere det. Gammel .xls-kryptering (RC4, RC4 CryptoAPI, XOR) er leselig: TXLSWorkbook.Open(FileName, Password) dekrypterer med et lagret passord, og de filene kan bli værende på den automatiserte stien. Krypterte OOXML-pakker går motsatt vei. HotXLS kan skrive en med SaveAsEncrypted, men den kan ikke lese en tilbake. OpenEncrypted kaster EXlsxEncryptionNotImplemented når den mottar en kryptert pakke, og det er derfor et ærlig mottaksdesign sender krypterte .xlsx til en person med Excel og holder den passordbærende .xls-en i kode
For batcharbeid fortjener denne klassifisereren plassen sin ved å kjøre over en hel innkommende mappe før noen arbeidsprosess starter reell behandling, siden hver sondering koster omtrent én filåpning og noen få kilobyte med lesing. Å legge den tidlig i løypa endrer feilmodusen driften faktisk bryr seg om. I stedet for at en jobb klokken tre om natten dør på fil 412 av 600, får du 412 filer i kø og 5 avvist ved mottak med en årsak festet til hver. Samme bibliotekkall, langt bedre driftshistorie
Spørsmålene et listekall ikke kan svare på
Navn og rekkefølge er alt du får. Listekallene sier ingenting om synlighet, så skjulte og svært skjulte ark ankommer listen og ser ut som alle andre. De rapporterer ingen brukte-område-dimensjoner, ingen celletall, og ingen dokumentegenskaper. docProps/core.xml-delen er også liten, men det finnes ingen egenskaper-bare-sondering i dag, så forfatter- og tittelmetadata koster fortsatt en full Open. Den ryddige måten å leve med det på, er å la de billige fakta rute hver fil og reservere de dyre for filer som overlever rutingen. For filene som faktisk går videre til en dyp lesing, kjører en skrivebeskyttet skanning av en stor .xls merkbart raskere med _DisableGraphics := True, som hopper over OfficeArt-parsing. Bare aldri lagre fra den instansen: tegnelaget den hoppet over, er borte fra modellen, og lagring ville droppet det fra filen
Filer som består triageringen, går som regel videre til dypere analyse. arbeidsbenken for arbeidsbokrevisjon og -konvertering dekker de tellerne per ark det er verdt å samle inn når en full åpning først er berettiget, og ytelsesveiledningen for store arbeidsbøker dekker hvordan man holder den fulle åpningen rask
HotXLS er et nativt Object Pascal-regnearkbibliotek for Delphi og C++Builder; hele API-overflaten, inkludert inspeksjonskallene vist her, er dokumentert på HotXLS Delphi Component-produktsiden