Ako je jedini posao poslužitelja emitiranje Excel datoteka, on nema nikakvog razloga pokretati Excel. Instaliranje Officea na agenta za izgradnju (build agent) ili uslugu izvješćivanja kako bi se njime upravljalo putem COM automatizacije pogrešan je dizajn, i to je pogrešan dizajn otkad ta praksa postoji. Sam Microsoft to kaže u smjernicama koje nisu ublažene već dvadeset godina: Office niti je napravljen niti je licenciran za automatizaciju iz automatskog procesa na strani poslužitelja. Ispravan odgovor je izravno pisanje BIFF i OOXML bajtova, bez ikakvog Excela u igri. To je cijela premisa HotXLS-a, nativne Object Pascal biblioteke koja sama čita i piše formate proračunskih tablica, tako da nema stolne aplikacije koja bi se mogla blokirati, curiti s memorijom ili se plaćati po radnom mjestu
Zašto upravljanje programom EXCEL.EXE iz usluge ne uspijeva
COM automatizacija daljinski upravlja stolnim programom, a stolni program potiho pretpostavlja tri stvari koje mu Windows usluga ne može pružiti: učitani korisnički profil, interaktivnu stanicu prozora (window station) i čovjeka koji gleda u zaslon. Uklonite to i kvarovi stižu u obliku koji se na računalu razvojnog programera nikada ne reproducira. Dijaloški okvir za oporavak datoteke, pogreška dodatka (add-in) ili dijaloški okvir za aktivaciju licence otvaraju se na radnoj površini koju nitko ne može vidjeti, a poziv automatizacije koji ga je pokrenuo nikada se ne vraća. Pozivatelj na kraju doživi vremensko ograničenje i ugasi se; instanca Excela to često ne učini, preživljavajući kao siroče koje drži zaključane datoteke i truje sljedeće pokretanje. Svatko tko je gledao kako se jedanaest zalutalih EXCEL.EXE procesa gomila pod računom usluge zna ostatak te priče
Priča o skaliranju nije ništa bolja čak i kada se ništa ne sruši. Instanca Excela je cjevovod za jednu radnu knjigu, svaki pristup svojstvu plaća cijenu međuprocesnog COM raspoređivanja (marshaling), a računalo na kojem se izvodi kod nosi licencu za Office čiji uvjeti isključuju upravo ovu upotrebu. Većina timova susreće se s tim ograničenjima kroz uzastopne ispade u radu, što je otprilike način na koji "umirovljenje COM sloja" završi na planu razvoja
Priča o zamjeni počinje rješavanjem jednog pitanja opsega jer ono odlučuje o tome koliko je posla stvarno potrebno. COM kod gotovo nikada ne postavlja samo vrijednosti ćelija. Poziva Workbook.SaveAs s konstantama formata, forsira ponovni izračun, postavlja postavke ispisa, a ponekad poseže i za međuspremnikom (clipboard). Prođite kroz stari kod i zapišite koja se od tih ponašanja zapravo isporučuju u izlazu, budući da svako od njih slijeće u drugi kut nativne biblioteke, a nekoliko njih (interoperabilnost međuspremnika je očigledan primjer) nema nikakvo značenje na strani poslužitelja i treba ih odbaciti radije nego portirati
Dva nativna mehanizma, dva modela vlasništva
HotXLS zamjenjuje proces Excela s dvije izravne implementacije formata. Mehanizam toka zapisa BIFF8 (TXLSWorkbook, jedinica lxHandle) rukuje .xls datotekama. Pisac paketa OOXML (TXLSXWorkbook, jedinica lxHandleX) proizvodi .xlsx koji je u skladu s ECMA-376 / ISO/IEC 29500. Nema se što registrirati niti instalirati na poslužitelju, a možete držati otvorenim onoliko radnih knjiga odjednom koliko memorija dopušta
Ono što ljude rano zbuni jest to što dva sučelja različito posjeduju svoju memoriju, a razlika je tiha sve dok se ne sruši:
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;
XLS sučelje ima brojanje referenci kroz sučelje IXLSWorkbook. Deklarirajte varijablu kao tip sučelja i nikada ne pozivajte Free na njoj; držite isti objekt u običnoj objektnoj varijabli i sami ga oslobodite, i brojač referenci će ga osloboditi drugi put. XLSX sučelje je običan objekt koji zahtijeva uobičajeni try..finally blok. Adresiranje ćelija temelji se na 1 s obje strane, što je jedino mjesto gdje se slažu. Zbirke listova se ne slažu: Entries na XLS strani se temelji na 1, indeksator XLSX Items se temelji on 0, a taj pomak za jedan se čisto prevodi na bilo koji način da ga pogrešno napišete i prikazuje se tek u vrijeme izvođenja
Pisanje radne knjige izravno u HTTP odgovor
Izvoz na strani poslužitelja obično nema razloga dodirivati disk. Privremene datoteke zahtijevaju politiku čišćenja, sudaraju se pod istodobnim zahtjevima i ostavljaju podatke klijenata na diskovima koje se nitko nije sjetio revidirati. Oba sučelja prihvaćaju TStream kroz svoja preopterećenja SaveAs, tako da radna knjiga može ići izravno u odgovor:
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;
Premotavanje je redak koji zaslužuje svoj komentar. SaveAs(Stream) piše s trenutne pozicije toka i nikada nakon toga ne traži povratak na nulu. Zaboravite Mem.Position := 0 i klijent dobiva preuzimanje od nula bajtova ili Excel javlja da je datoteka oštećena. Ovo je najčešća pogreška u kodu radne knjige okrenutom prema webu, i najsurovija, jer prolazi pored bilo kojeg jediničnog testa koji samo tvrdi da tok ima duljinu različitu od nule
Jedna rutina za izgradnju radne knjige doseže svaki drugi format isporuke bez restrukturiranja. SaveAsCSV odgovara na zahtjev "samo mi daj sirove podatke", SaveAsHTML rukuje s "ispusti na stranicu portala", SaveAsRTF hrani cjevovode dokumenata, a SaveAsODS pokriva OpenDocument mandat, sve s preopterećenjima datoteka i tokova. Jedna rutina izvoza plus parametar formata zamjenjuje ono što su obično bila četiri zasebna COM makronaredbe. Opcije HTML izvoznika TXLSXHtmlExportOptions nose naslov, CSS klasu i prekidač fragment-ili-cijeli-dokument, što drži portal izvan posla uređivanja izvezenih oznaka regularnim izrazima
Vrijednosti formula bez procesa Excela koji bi ih izračunao
Pod COM automatizacijom Excel je ponovno izračunavao sve besplatno, a odbacivanje COM-a to tiho ukida. SaveAs pohranjuje formule kao tekst bez njihova izračuvanja; brojevi se pojavljuju tek kada Excel otvori datoteku i ponovno izračuna vrijednosti, što je ponašanje koje XLS sučelje omogućuje prilagoditi putem RecalcOnSave i CalculationMode. Za datoteku koja ide osobi to je točno ono što treba. Pogrešno je za uslugu koja mora potvrditi ukupni iznos prije slanja, i pogrešno za izvoz u CSV, koji zapisuje tekst formule umjesto njezina rezultata. U oba slučaja procjena se mora izvršiti na poslužitelju s ugrađenim mehanizmom:
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 sučelja ovdje ponovno stvara probleme. XLSX strana dodjeljuje izraze putem Cell.Formula bez znaka jednakosti; XLS strana ih piše putem Cell.Value s vodećim '='. Prenesite kod s jednog na drugi nepromijenjen i kriva konvencija će pohraniti tekstualni niz koji samo sliči na formulu, bez ikakve pogreške koja bi na to ukazala. Kada formule radne knjige trebaju dosegnuti vašu vlastitu poslovnu logiku, povratni poziv OnUserFunction omogućuje mehanizmu da preda nepoznate nazive funkcija Delphi kodu u vrijeme procjene. To je nativna zamjena za UDF dodatke (add-ins) koji se obično skrivaju unutar samih proračunskih tablica oko kojih je izrastao COM automatizacijski sustav
Rubovi implementacije koji se pojavljuju samo na poslužitelju
Nekoliko detalja odlučuje hoće li uvođenje biti čisto ili zbunjujuće, a prvi je grafikon jedinica. Izvoznik skupa podataka povuci-i-ispusti TDataToXLS povlači VCL Forms, Controls i Dialogs. Bezopasno u stolnom alatu; u konzolnoj usluzi vuče cijeli VCL za sobom. Jezgrene jedinice lxHandle i lxHandleX dostižu samo Windows, Classes, SysUtils i Variants, pa je za čistu uslugu bolje napisati vlastitu petlju skupa podataka prema jezgrovnom API-ju nego uvesti komponentu radi praktičnosti
Zatim, tu je višenitnost. Instance radne knjige nisu sigurne za višenitno dijeljenje (thread-safe), ali ne dijele ni bilo kakvo globalno stanje, pa je uzorak koji se skalira najjednostavniji: objekt radne knjige po poslu ili po radnoj niti. To donosi paralelno generiranje izvješća, što jedna zajednička instanca Excela nikada ne može učiniti. Rukovatelj zahtjevima koji stvara, popunjava, sprema i oslobađa vlastitu radnu knjigu uopće ne treba zaključavanje, a radijus eksplozije kvara kolabira s "zajednička instanca Excela je blokirana za sve" na "ovaj jedan zahtjev je pokrenuo iznimku", s čime vaše postojeće rukovanje pogreškama već zna što učiniti
Ciljanje formata je posljednje od njih. TXLSWorkbook.SaveAs piše BIFF (xlExcel97) prema zadanim postavkama, a guranje XLS sadržaja u .xlsx prolazi kroz most SaveXLSWorkbookAsXLSX uz smanjenu vjernost. Odaberite sučelje prema formatu koji namjeravate isporučiti, u vrijeme projektiranja, radije nego da gradite u jednom i pretvarate na kraju cjevovoda
Za polovicu učitavanja podataka tipičnog projekta zamjene, uzorci izvoza baze podataka u radnu knjigu pokrivaju i komponentu i ručno pisanu petlju, a kada broj redaka dosegne šesteroznamenkasti iznos, tehnike performansi velikih radnih knjiga čine razliku između minuta i sekundi. Izvješća izgrađena iz izgleda koje održavaju dizajneri pokrivena su u vodiču kroz generiranje izvješća na temelju predloška
HotXLS se isporučuje kao Object Pascal izvor za Delphi i C++Builder; izdanja, licenciranje i cjelovita API referenca nalaze se na stranici proizvoda HotXLS komponente