Če je edino opravilo strežnika oddajanje Excelovih datotek, nima razloga za poganjanje Excela. Nameščanje Officea na agenta za gradnjo ali poročevalsko storitev, da ga krmilite prek COM avtomatizacije, je napačna zasnova, in bila je napačna zasnova, odkar ta praksa obstaja. Microsoft sam pravi tako v smernicah, ki se dvajset let niso omehčale: Office ni niti zgrajen niti licenciran za avtomatizacijo iz nenadzorovane strežniške strani. Pravi odgovor je neposredno pisanje bajtov BIFF in OOXML, brez Excela v sliki. To je celotna premisa HotXLS, izvorne knjižnice Object Pascal, ki sama bere in piše formate preglednic, zato ni namizne aplikacije za blokiranje, puščanje ali licenciranje na sedež.
Zakaj poganjanje EXCEL.EXE iz storitve ne deluje
COM avtomatizacija daljinsko krmili namizni program, namizni program pa tiho predpostavlja tri stvari, ki mu jih storitev Windows ne more zagotoviti: naložen uporabniški profil, interaktivno postajo oken in človeka, ki gleda zaslon. Odvzemite te in napake prispejo v obliki, ki je nobena razvijalska naprava nikoli ne reproducira. Poziv za obnovitev datoteke, napaka vtičnika ali dialog za aktivacijo licence se odpre na namizju, ki ga nihče ne vidi, klic avtomatizacije, ki ga je sprožil, pa se nikoli ne vrne. Klicatelj sčasoma prekoračit čas in odmre; primerka Excel pogosto ne, preostane kot sirota, ki drži zaklepanja datotek in zastrupi naslednje zaganjanje. Kdorkoli je gledal, kako se pod računom storitve nabira enajst pogrešanih procesov EXCEL.EXE, pozna nadaljevanje te zgodbe.
Zgodba o skaliranju ni boljša niti ko nič ne sesuje. Primerek Excel je cevovod za en delovni zvezek, vsak dostop do lastnosti plača strošek medprocesnega COM zbiranja, in škatla, ki poganja kodo, nosi licenco za Office, katere pogoji izključujejo točno to rabo. Večina ekip te meje spozna eno izklop naenkrat, kar je otprilike, kako "upokoji plast COM" pristane na načrtu.
Preden se prenovitev začne, razrešite eno vprašanje obsega, ker odloča, koliko dela je resnično. COM koda skoraj nikoli ne nastavi le vrednosti celic. Kliče Workbook.SaveAs s formatnimi konstantami, prisili preračunavanje, posreduje nastavitve tiskanja, včasih seže po odložišče. Preglejte staro kodo in zapišite, katera od teh obnašanj se dejansko pošlje v izhodu, ker vsako pristane v drugem kotičku izvorne knjižnice, in par od njih (interop z odložiščem je očitna) nima strežniške strani pomena in bi ga morali opustiti in ne prenesti.
Dve izvorni procesni mašini, dva modela lastništva
HotXLS zamenja proces Excel z dvema neposrednima implementacijama formata. Mašina toka zapisov BIFF8 (TXLSWorkbook, enota lxHandle) obravnava .xls. Pisalnik paketov OOXML (TXLSXWorkbook, enota lxHandleX) proizvaja .xlsx, ki je skladen z ECMA-376 / ISO/IEC 29500. Ni ničesar za registracijo in ničesar za namestitev na strežnik, in hkrati imate lahko odprtih toliko delovnih zvezkov, kolikor dovoli pomnilnik.
Kar ljudi sprva zbega, je to, da obe fasadi upravljata pomnilnik različno, in razlika je tiha, dokler ne sesuje:
var
Book: IXLSWorkbook; // interface reference: released automatically
Sheet: IXLSWorksheet;
BookX: TXLSXWorkbook; // plain object: you free it
SheetX: TXLSXWorksheet;
begin
// BIFF8 .xls output - no Free; the interface refcount owns it
Book := TXLSWorkbook.Create;
Sheet := Book.Sheets.Add;
Sheet.Name := 'Report';
Sheet.Cells.Item[1, 1].Value := 'Generated without Excel';
Book.SaveAs('report.xls');
// OOXML .xlsx output - explicit lifetime
BookX := TXLSXWorkbook.Create;
try
SheetX := BookX.Sheets.Add('Report');
SheetX.Cells[1, 1].Value := 'Generated without Excel';
BookX.SaveAs('report.xlsx');
finally
BookX.Free;
end;
end;
Fasada XLS je s štetjem referenc prek vmesnika IXLSWorkbook. Spremenljivko razglasite kot tip vmesnika in nikoli ne kličite Free nanjo; hranite isti objekt v navadni spremenljivki objekta in ga sami osvobodite, refcount pa ga sprosti drugič. Fasada XLSX je navaden objekt, ki želi navaden try..finally. Naslavljanje celic je z osnovo 1 na obeh straneh, kar je eno mesto, kjer se obe strinjata. Zbirke listov ne: Entries na strani XLS je z osnovo 1, indekser XLSX Items je z osnovo 0, in ta pomik za eno se prevede čisto v katero koli smer in se pokaže le pri zagonu.
Pisanje delovnega zvezka neposredno v HTTP odziv
Strežniški izvoz navadno nima razloga za dotikanje diska. Začasne datoteke zahtevajo politiko čiščenja, se trčijo pri sočasnih zahtevah in puščajo podatke strank na zvezkih, ki jih nihče ni pomislil revidirati. Obe fasadi sprejmeta TStream prek preobremenitev SaveAs, tako da delovni zvezek gre neposredno v odziv:
Mem := TMemoryStream.Create;
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Data');
Sheet.Cells[1, 1].Value := 'Generated ' + DateTimeToStr(Now);
Book.SaveAs(Mem); // writes from the CURRENT stream position
Mem.Position := 0; // rewind before handing the stream over
Response.ContentType :=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
Response.ContentStream := Mem; // the framework now owns Mem
finally
Book.Free;
end;
Navijanje nazaj je vrstica, ki zasluži komentar. SaveAs(Stream) piše od trenutnega položaja toka in se nikoli ne vrne nazaj na nič. Pozabite Mem.Position := 0 in stranka dobi prenos z nič bajti ali Excel pokliče datoteko poškodovano. To je najpogostejša napaka v kodi delovnih zvezkov, ki so obrnjeni na splet, in najokrutnejša, ker mimo vsake enote testa, ki samo ugotovi, da tok ima neničelno dolžino.
Ena rutina za gradnjo delovnih zvezkov doseže vse druge formate dostave brez prestrukturiranja. SaveAsCSV odgovori na zahtevo "samo daj mi surove podatke", SaveAsHTML obravnava "spusti v stran portala", SaveAsRTF napaja dokumentne cevovode, in SaveAsODS pokriva mandat OpenDocument, vse z preobremenjitvami za datoteke in tokove. Ena izvozna rutina plus parameter formata nadomesti, kar je navadno bilo štiri ločeni COM makri. TXLSXHtmlExportOptions za izvoznik HTML nosi naslov, razred CSS in stikalo fragment-ali-celoten-dokument, ki ohranja primer portala izven poslovanja z urejanjem regex izvoženega označevanja.
Vrednosti formul brez procesa Excel za njihov izračun
Pod COM avtomatizacijo je Excel brezplačno preračunal vse, in opuščanje COM to tiho odvzame. SaveAs shranjuje formule kot besedilo, ne da bi jih ovrednotil; številke se pojavijo šele, ko Excel odpre datoteko in preračuna, obnašanje, ki ga fasada XLS omogoča uglasiti prek RecalcOnSave in CalculationMode. Za datoteko namenjeno osebi je to točno prav. Napačno je za storitev, ki mora potrditi skupni seštevek, preden ga pošlje, in napačno za izvoz CSV, ki namesto rezultata piše besedilo formule. V obeh primerih morate ovrednotiti na strežniku z vgrajenim pogonom:
SheetX.Cells[1, 1].Value := 1200;
SheetX.Cells[2, 1].Value := 950;
SheetX.Cells[3, 1].Formula := 'SUM(A1:A2)'; // XLSX facade: no '=' prefix
Total := BookX.Calculate('SUM(A1:A2)'); // evaluate on the server, now
if Total <> 2150 then
raise Exception.Create('reconciliation failed before delivery');
Konvencija fasade znova ugrizne tukaj. Stran XLSX dodeli izraze prek Cell.Formula brez znaka enakosti; stran XLS jih piše prek Cell.Value z vodilnim '='. Prenesite kodo iz enega v drugega nespremenjeno in napačna konvencija shrani besedilni niz, ki le spominja na formulo, brez napake za označevanje. Ko formule delovnega zvezka morajo seči v vašo lastno poslovno logiko, povratni klic OnUserFunction pogonu omogoča, da neznana imena funkcij ob ovrednotenju preda kodi Delphi. To je izvorna zamenjava za UDF vtičnike, ki so pogosto skriti znotraj preglednic, ki so jih obdajale sistemi COM avtomatizacije.
Robovi uvajanja, ki se pokažejo šele na strežniku
Nekaj podrobnosti odloča, ali je uvajanje čisto ali zmedeno, in prva je graf enot. Izvoznik nabora podatkov z vleci in spusti TDataToXLS potegne za seboj VCL Forms, Controls in Dialogs. Neškodljivo v namiznem orodju; v konzolni storitvi pa za seboj potegne celoten VCL. Jedrne enote lxHandle in lxHandleX segajo le po Windows, Classes, SysUtils in Variants, zato je za čisto storitev bolje napisati lastno zanko nabora podatkov glede na jedrni API in ne uvažati komponente za udobje.
Sledi navoj. Primerki delovnih zvezkov niso varni za niti, toda nobene globalne stanje si ne delijo, zato je vzorec, ki se skalira, najpreprostejši: objekt delovnega zvezka na opravilo ali na delavsko nit. To prinaša vzporedno generiranje poročil, kar enoten deljen primerek Excel nikoli ne more. Upravljalnik zahtev, ki ustvari, zapolni, shrani in sprosti lasten delovni zvezek, ne potrebuje nobenih zaklepanj, in polmer eksplozije napake se sesede iz "deljen primerek Excel je blokiran za vse" na "ta ena zahteva je dvignila izjemo", s čimer vaše obstoječe ravnanje z napakami že ve, kaj storiti.
Ciljanje formata je zadnje od njih. TXLSWorkbook.SaveAs privzeto piše BIFF (xlExcel97), in potiskanje vsebine XLS v .xlsx poteka prek mostu SaveXLSWorkbookAsXLSX pri zmanjšani zvestobi. Na začetku izberite fasado glede na format, ki ga nameravate dostaviti, in ne gradite v eni in pretvarjate na koncu cevovoda.
Za del nalaganja podatkov tipičnega projekta zamenjave vzorci izvoza baze podatkov v delovni zvezek pokrivajo tako komponento kot ročno napisano zanko, in ko število vrstic doseže šest številk, tehnike zmogljivosti za velike delovne zvezke postanejo razlika med minutami in sekundami. Poročila, zgrajena iz postavitev, ki jih vzdržuje oblikovalec, so pokrita v navodilih za generiranje poročil predloge.
HotXLS je dostavljen kot izvorna koda Object Pascal za Delphi in C++Builder; izdaje, licenciranje in celotna referenca API so na strani HotXLS Component.