Techninis straipsnis

Excel failu generavimas Delphi be Office automatizavimo

Jei serverio vienintelis darbas yra iskleisti Excel failus, jam nereikia veikti Excel. Office instaliacij i kurybos agento arba ataskaitu tarnybos, siekiant vairuoti ja per COM automatizavima, yra netinkamas projektavimas, ir jis buvo netinkamas projektavimas tiek, kiek egzistuoja cia praktika. Pats Microsoft tai sako, nuodugnios rekomendacijos, kurios nesuminkstejo per dvidesimt metu: Office nera sukurtas ir nelicencijuotas buti automatizuotas is neprziurimo, serverio pusio proceso. Tinkamas atsakymas yra tiesiogiai rasyti BIFF ir OOXML baitus, be Excel jokiu. Tai yra visa HotXLS premisa, gimtoji Object Pascal biblioteka, kuri pati skaito ir raso skaiciuokliniu formatus, todel nera stalinis programa kabeti, nuoteketi arba moketi vienam sedimai.

Kodel vairuoti EXCEL.EXE is tarnybos nepasiseka

COM automatizavimas nuotoliniu buda kontroliuoja stalinia programa, o stalinio programa tykiai prielaido tris dalykus, kurių Windows tarnyba negali jam teikti: ikeltas vartotojo profilis, interaktyvu lango stoteles ir zmogus stebi ekrana. Pasalinkite juos ir nesekmes atvyksta forma, kurios jokia kurejo masina niekada neatgamina. Failo-atkurimo raginimu, priedinis klaida arba licencijos-aktyvacijos dialogo atsidaro darbalaukyje, kurio niekas nemato, o automatizavimo kvietimas, kuris ji paleido, niekada nebegrazinta. Iskviektojaus galiausiai baigia laiko ir mirsra; Excel instancija daznai to nedaro, issigyvena kaip isnagastas, kuris laiko failu uzraktus ir nuodija kita vykdyma. Bet kas, stebejęs vienuolika atsitiktinIo EXCEL.EXE procesu kaupia po tarnybos paskyra, zino likusios istorijos dali.

Mastelio istorija nera geresne, net kai niekas nesuyra. Excel instancija yra vienos-darbaknyges konvejeris, kiekvienos savybes prieiga moka saltines-proceso COM marshaling kaina, ir deze, vykdanti koda, nesha Office licencija, kurios salygos iskelia butent si naudojima. Dauguma komandu susitinka su siais apribojimais viena incidenta vienu metu, kas yra griztumai, kaip "istrinti COM sluoksni" atsiduria keliu zemelapis.

Pries tas perrasymas prasideda, ipreskte viena srities klausima, nes jis nusiprendzia, kiek darbo yra tikras. COM kodas beveik niekada tik nustato lasteleiu reiksmes. Jis kviecia Workbook.SaveAs su formato konstantomis, forsuoja perskaiciavima, stumia spausdinimo konfigūracija, kartais siekia mainaplokes. Eikite per sen koda ir parasyti, kurie is siu elgesiu is tikruju atsiuncia isvestu, nes kiekvienas nusileido skirtingame kampe gimtosios bibliotekos, ir keliems is ju (mainaplokes sąveika yra akivaizdu) neturi serverio pusio reiksmes ir turetu buti paleidimo, o ne pernesimai.

Du gimtieji vaikliai, du nuosavybes modeliai

HotXLS pakeicia Excel procesa dviem tiesioginem formato implementacijoms. BIFF8 irasu-srauto variklis (TXLSWorkbook, modulyje lxHandle) tvarko .xls. OOXML paketo rasytojus (TXLSXWorkbook, modulyje lxHandleX) sukuria .xlsx, atitinkanti ECMA-376 / ISO/IEC 29500. Serveris neturi ka registruoti ir nieko instaliuoti, o atminties leidzia laikyti atidarytas tiek darbaknyges, kiek leidzia atmintis.

Kas suklaidina zmones is pradziu yra tai, kad du fasadai valdo savo atminti skirtingai, ir skirtumas yra tylus, kol nesutrinka:

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 fasadas yra suskaiciuotas nuorodomis per IXLSWorkbook sasiaja. Deklaruokite kintamaji kaip sasajos tipu ir niekada neskambinkite Free ant jos; laikykite ta pati objekta paprastu objekto kintamajame ir laisvinkite ji pats, ir nuorodų skaiciavimas ji paleidos antra karta. XLSX fasadas yra paprastas objektas, norintis paprastu try..finally. Lasteleiu adresavimas yra 1-pagrindinis abiems pusems, kas yra vienas vietas, kurioje abu susitaria. Lapu kolekcijos ne: Entries XLS puseje yra 1-pagrindiniai, XLSX Items indeksavimas yra 0-pagrindiniai, ir tas vieno-perstumimas surenka svariai, kuriuo bet kuriuo kuriuo gaunate klaidingai ir parodo save tik vykdymo metu.

Darbaknyges rasymas tiesiai i HTTP atsakyma

Serverio puses eksportas paprastai neturi priezasties liesti disko. Laikinieji failai reikalauja valymo politikos, susiduria su vienalaikemis uzklausomis ir palieka kliento duomenis ant tomu, kuriu niekas nemanete audituoti. Abu fasadai ima TStream per savo SaveAs perkrovimus, todel darbaknyge gali tiesiai eiti i atsakyma:

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;

Atsukimas yra eilute, kuri uzdirbana komentara. SaveAs(Stream) raso nuo srauto dabartines pozicijos ir niekada neskuba atgal i nuli veliau. Uzmirskte Mem.Position := 0 ir klientas gauna nuliniu baitu atsisiuntimą, arba Excel vadina faila sugadinto. Tai yra dazniausiai pasitaikanti klaida ziniatiinkliu nukreiptos darbaknyges kode, ir ziauriausias, nes ji praeina bet kokia vieneto bandyma, kuris tik teigia, kad srautas turi neiseinancius ilgi.

Viena darbaknyges-kurimo rutina pasiekia kiekviena kita pristatymo formata be perstrukturizavimo. SaveAsCSV atsako "tik duoti man zaliuosius duomenis" uzklausą, SaveAsHTML tvarko "paskleisti i portalo puslapio", SaveAsRTF maitina dokumentu konvejerius, ir SaveAsODS apima OpenDocument igpareigojima, visus su failu ir srauto perkrovimais. Viena eksporto rutina su formato parametru pakeicia tai, kas buvo dazniausiai keturi atskiri COM makrosai. HTML eksportuotojo TXLSXHtmlExportOptions nesha pavadinima, CSS klase ir fragmentu-arba-pilno-dokumento jungikliu, kuris laiko portalo atveji is verslo regex-redagavimo eksportuotos zymejimo.

Formules reiksmes be Excel proceso jas apskaiciuoti

Esant COM automatizavimui, Excel perskaiciavo viska nemokamai, ir pametant COM tykiai atsakauja. SaveAs saugo formules kaip teksta neivykdinant jas; skaiciai tik atrodo, kai Excel atidaro faila ir perskaiciuoja, elgesys, kuri XLS fasadas leidzia jums valdyti per RecalcOnSave ir CalculationMode. Failui, skirtos zmogui, tai yra tiksliai teisinga. Ji neteisinga tarnyba, kuri turi patvirtinti suma pries issiuncia, ir neteisinga CSV eksportui, kuris raso formules teksta, o ne jos rezultata. Bet kuriuo atveju reikia ivykdyti serveryje su integruotu varikliu:

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');

Fasado konvencija vel kanda cia. XLSX puseje priskiria israiskas per Cell.Formula be lygybés zenklou; XLS puseje jas raso per Cell.Value su pirmaujancio '='. Nesioti kodą is vienos i kita be pakeitimo ir klaidinga konvencija saugoja teksto eilute, kuri tik primena formule, be klaidos to pažymejimui. Kai darbaknyges formuliai reikia pasiekti i jusu verslo logika, OnUserFunction atsaukimas leidzia varikliui perduoti nezinomus funkcijų pavadinimus Delphi kodui ivykdymo metu. Tai yra gimtasis pakaitalas UDF priedams, kurie linkę sleptis paciuose skaiciuoklinese lenteluose, apie kurias augino COM automatizavimo sistema.

Dislokavimo krastai, kurie atsiranda tik serveryje

Keletas detaliu nusprendzia, ar paleidimas yra svarus arba gluminantis, ir pirmas yra vieneiu grafas. Vilkimo-ir-leidimo duomenu rinkinio eksportuotojas TDataToXLS istraukia VCL Forms, Controls ir Dialogs. Nekenksminga staliniame irankis; konsoline tarnyba vilkia visa VCL uz nes. Bazines vieneiai lxHandle ir lxHandleX siekia tik Windows, Classes, SysUtils ir Variants, todel gryna tarnyba geriau rasyti savo duomenu rinkiniu cikla, veiksminga bazinio API negu importuojant komponenta patogumui.

Tada yra gljos. Darbaknyges instancijos nera gijoms saugios, taciau jos taip pat nesidalija jokia globalia busena, todel didelio mastelio schema yra paprasciausias: vienas darbaknyges objektas vienai uzduociai arba vienai darbininko gijai. Tai perka lygiagretų ataskaitu generavima, ką viena bendra Excel instancija niekada negali padaryti. Uzklausa tvarkytuvas, kuris sukuria, uzpildo, issaugo ir laisvina savo darbaknygę, nereikalauja jokiu uzraktu, ir nesekmes sprogimu ratas susitraukia nuo "bendra Excel instancija neverikiausiai susiraza visiems" iki "si viena uzklausą isskele isimti", kurią jusu egzistuojantis klaidu tvarkymas jau zino, ka su ja daryti.

Formato taikymas yra paskutinis is ju. TXLSWorkbook.SaveAs raso BIFF (xlExcel97) pagal numatytaji, ir XLS turinio stumimas i .xlsx veikia per SaveXLSWorkbookAsXLSX tilta sumazintu tikslumu. Pasirinkite fasada pagal formata, kuri ketinate siusti, projektavimo metu, o ne kurti viename ir konvertuoti konvejerio pabaigoje.

Duomenu ikrovimo pusei tipisko pakeitimo projekto, duomenu bazes-i-darbaknyge eksporto modeliai apima tiek komponenta, tiek ranka rasytu ciklą, ir kai eiluciu skaiciai pasiekia sesiatainI sifrą dideles-darbaknyges nasumas technikos tampa skirtumu tarp minuciu ir sekunciu. Ataskaitos, sukurtos is projektuotojo-valdomu isdestymu, aptariamos sabalo ataskaitu generavimo ikampime.

HotXLS pristato kaip Object Pascal saltinis Delphi ir C++Builder; versijos, licenciavimas ir pilnas API nuoroda yra HotXLS Component produkto puslapyje.