Jos palvelimen ainoa tehtävä on tuottaa Excel-tiedostoja, sillä ei ole mitään asiaa ajaa Exceliä. Officen asentaminen käännösagenttiin tai raportointipalveluun, jotta sitä voi ohjata COM-automaatiolla, on väärä suunnitteluvalinta, ja se on ollut sitä niin kauan kuin käytäntö on ollut olemassa. Microsoft sanoo saman itse ohjeistuksessaan, joka ei ole pehmentynyt kahteenkymmeneen vuoteen: Officea ei ole rakennettu eikä lisensoitu automatisoitavaksi valvomattomasta palvelinpuolen prosessista. Oikea ratkaisu on kirjoittaa BIFF- ja OOXML-tavut suoraan ilman Exceliä. Se on HotXLS:n koko lähtökohta: natiivi Object Pascal -kirjasto lukee ja kirjoittaa laskentataulukkomuodot itse, joten ei ole työpöytäsovellusta, joka voisi jumittua, vuotaa muistia tai vaatia käyttäjäkohtaista lisenssiä
Miksi EXCEL.EXE:n ajaminen palvelusta epäonnistuu
COM-automaatio etäohjaa työpöytäohjelmaa, ja työpöytäohjelma olettaa huomaamatta kolmea asiaa, joita Windows-palvelu ei voi tarjota: ladatun käyttäjäprofiilin, vuorovaikutteisen ikkunatyöaseman ja ihmisen katsomassa näyttöä. Kun poistat ne, virheet saapuvat muodossa, jota millään kehittäjän koneella ei voi toistaa. Tiedostonpalautuskehote, apuohjelmavirhe tai lisenssin aktivointivalintaikkuna avautuu työpöydälle, jota kukaan ei näe, eikä sen käynnistänyt automaatiokutsu koskaan palaa. Kutsuja aikakatkaistaan ja kuolee; Excel-esiintymä ei usein kuole, vaan jää orvoksi pitämään tiedostolukkoja ja myrkyttämään seuraavan ajon. Jokainen, joka on nähnyt yksitoista irrallista EXCEL.EXE-prosessia kasaantumassa palvelutilin alle, tuntee tarinan lopun
Skaalautuvuuden tarina ei ole parempi, vaikka mikään ei kaatuisi. Excel-esiintymä on yhden työkirjan käsittelyputki, jokainen ominaisuuden käyttö maksaa prosessien välisen COM-marshalloinnin hinnan, ja koodia ajavalla koneella on Office-lisenssi, jonka ehdot sulkevat juuri tämän käyttötavan pois. Useimmat tiimit kohtaavat nämä rajat yksi käyttökatko kerrallaan, minkä vuoksi "COM-kerroksen poistaminen käytöstä" päätyy tiekartalle
Ennen kuin uudelleenkirjoitus alkaa, ratkaise yksi laajuuskysymys, sillä se määrää, kuinka paljon työstä on todellista. COM-koodi ei lähes koskaan vain aseta soluarvoja. Se kutsuu Workbook.SaveAs-metodia muotovakioilla, pakottaa uudelleenlaskennan, asettaa tulostusasetuksia ja joskus käyttää leikepöytää. Käy vanha koodi läpi ja kirjaa, mitkä näistä toiminnoista todella näkyvät tulosteessa, sillä kukin kuuluu natiivikirjaston eri kulmaan, ja parilla niistä (leikepöytäyhteentoimivuus on ilmeisin) ei ole palvelinpuolella merkitystä, joten ne on jätettävä pois porttaamisen sijaan
Kaksi natiivimoottoria, kaksi omistajuusmallia
HotXLS korvaa Excel-prosessin kahdella suoralla muotototeutuksella. BIFF8-tietuevirran moottori (TXLSWorkbook, yksikkö lxHandle) käsittelee .xls-tiedostoja. OOXML-pakettikirjoittaja (TXLSXWorkbook, yksikkö lxHandleX) tuottaa ECMA-376 / ISO/IEC 29500 -standardin mukaisia .xlsx-tiedostoja. Palvelimelle ei tarvitse rekisteröidä eikä asentaa mitään, ja voit pitää avoinna niin monta työkirjaa kuin muisti sallii
Ihmiset kompastuvat varhain siihen, että kaksi julkisivua omistaa muistinsa eri tavoin, ja ero pysyy hiljaisena siihen asti, kunnes se kaataa ohjelman:
var
Book: IXLSWorkbook; // liittymäviittaus: vapautetaan automaattisesti
Sheet: IXLSWorksheet;
BookX: TXLSXWorkbook; // tavallinen olio: sinä vapautat sen
SheetX: TXLSXWorksheet;
begin
// BIFF8 .xls -tuloste - ei Free-kutsua; liittymän viittauslaskuri omistaa sen
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 -tuloste - nimenomainen elinaika
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-julkisivu käyttää viitelaskentaa IXLSWorkbook-rajapinnan kautta. Määritä muuttuja rajapintatyypiksi äläkä koskaan kutsu sille Free-metodia; jos pidät samaa objektia tavallisessa objektimuuttujassa ja vapautat sen itse, viitelaskenta vapauttaa sen toistamiseen. XLSX-julkisivu on tavallinen objekti, joka tarvitsee tavallisen try..finally-lohkon. Soluosoitteistus on molemmilla puolilla 1-pohjainen, mikä on ainoa kohta, jossa ne ovat samaa mieltä. Laskentataulukkokokoelmat eivät ole: XLS-puolen Entries on 1-pohjainen, XLSX:n Items-indeksoija on 0-pohjainen, ja kummankin suunnan yhden indeksin virhe kääntyy puhtaasti ja paljastuu vasta ajonaikana
Työkirjan kirjoittaminen suoraan HTTP-vastaukseen
Palvelinpuolen viennillä ei yleensä ole syytä koskea levyyn. Väliaikaistiedostot vaativat siivouskäytännön, törmäävät samanaikaisissa pyynnöissä ja jättävät asiakastietoja levyille, joita kukaan ei tullut tarkastaneeksi. Molemmat julkisivut hyväksyvät TStream-virran SaveAs-ylikuormitustensa kautta, joten työkirja voidaan kirjoittaa suoraan vastaukseen:
Mem := TMemoryStream.Create;
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Data');
Sheet.Cells[1, 1].Value := 'Generated ' + DateTimeToStr(Now);
Book.SaveAs(Mem); // kirjoittaa NYKYISESTÄ stream-sijainnista
Mem.Position := 0; // kelaa taaksepäin ennen streamin luovutusta
Response.ContentType :=
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
Response.ContentStream := Mem; // kehys omistaa nyt Mem-olion
finally
Book.Free;
end;
Takaisinkelaus on rivi, joka ansaitsee kommenttinsa. SaveAs(Stream) kirjoittaa virran nykyisestä sijainnista eikä koskaan hakeudu takaisin nollaan. Jos unohdat Mem.Position := 0, asiakas saa nollatavuisen latauksen tai Excel kutsuu tiedostoa vioittuneeksi. Tämä on yleisin verkkokäyttöisen työkirjakoodin virhe ja julmin niistä, sillä se pääsee läpi kaikista yksikkötesteistä, jotka vain tarkistavat virran pituuden olevan nollaa suurempi
Yksi työkirjanrakennusrutiini tavoittaa kaikki muut toimitusmuodot ilman uudelleenjärjestelyä. SaveAsCSV vastaa pyyntöön "anna vain raakadata", SaveAsHTML hoitaa pyynnön "upota se portaalisivulle", SaveAsRTF syöttää dokumenttiputkia ja SaveAsODS kattaa OpenDocument-vaatimuksen, kaikki sekä tiedosto- että virta-ylikuormituksina. Yksi vientirutiini ja muotoparametri korvaavat sen, mikä yleensä oli neljä erillistä COM-makroa. HTML-viejän TXLSXHtmlExportOptions sisältää otsikon, CSS-luokan sekä fragmentti- tai kokodokumenttikytkimen, joten portaalia varten ei tarvitse muokata vietyä merkintää säännöllisillä lausekkeilla
Kaava-arvot ilman Excel-prosessia, joka laskee ne
COM-automaation alla Excel laski kaiken uudelleen ilmaiseksi, ja COM:n poistaminen peruu sen huomaamatta. SaveAs tallentaa kaavat tekstinä niitä laskematta; luvut ilmestyvät vasta, kun Excel avaa tiedoston ja laskee ne uudelleen. XLS-julkisivussa voit säätää tätä toimintaa RecalcOnSave- ja CalculationMode-ominaisuuksilla. Ihmiselle menevässä tiedostossa tämä on juuri oikein. Se on väärin palvelulle, jonka on vahvistettava loppusumma ennen toimitusta, ja väärin CSV-viennille, joka kirjoittaa kaavatekstin tuloksen sijaan. Molemmissa tapauksissa laskenta on tehtävä palvelimella sisäänrakennetulla moottorilla:
SheetX.Cells[1, 1].Value := 1200;
SheetX.Cells[2, 1].Value := 950;
SheetX.Cells[3, 1].Formula := 'SUM(A1:A2)'; // XLSX-julkisivu: ei '='-etuliitettä
Total := BookX.Calculate('SUM(A1:A2)'); // arvioi palvelimella nyt
if Total <> 2150 then
raise Exception.Create('reconciliation failed before delivery');
Julkisivukäytäntö puree jälleen tässä. XLSX-puoli asettaa lausekkeet Cell.Formula-ominaisuudella ilman yhtäsuuruusmerkkiä; XLS-puoli kirjoittaa ne Cell.Value-ominaisuuden kautta alussa olevalla '='-merkillä. Jos siirrät koodin sellaisenaan yhdestä toiseen, väärä käytäntö tallentaa tekstimerkkijonon, joka vain muistuttaa kaavaa, ilman virhettä, joka paljastaisi sen. Kun työkirjan kaavojen on ulotuttava omaan liiketoimintalogiikkaasi, OnUserFunction-takaisinkutsu antaa moottorin välittää tuntemattomat funktioiden nimet Delphi-koodille laskenta-aikana. Se on natiivi vastine käyttäjän määrittämien funktioiden apuohjelmille, jotka tapaavat piileskellä juuri niissä laskentataulukoissa, joiden ympärille COM-automaatiota käyttävä järjestelmä on kasvanut
Käyttöönoton reunat, jotka näkyvät vain palvelimella
Muutama yksityiskohta ratkaisee, onko käyttöönotto siisti vai hämmentävä, ja ensimmäinen niistä on yksikkökaavio. Vedä ja pudota -aineistoviejä TDataToXLS tuo mukanaan VCL:n Forms-, Controls- ja Dialogs-yksiköt. Työpöytätyökalussa se on harmitonta; konsolipalvelussa se raahaa mukanaan koko VCL:n. Ydinyksiköt lxHandle ja lxHandleX käyttävät vain yksiköitä Windows, Classes, SysUtils ja Variants, joten puhtaassa palvelussa on parempi kirjoittaa oma aineistosilmukka ydinrajapintaa vasten kuin tuoda komponentti mukavuuden vuoksi
Sitten on säikeistys. Työkirjaesiintymät eivät ole säieturvallisia, mutta ne eivät myöskään jaa globaalia tilaa, joten skaalautuva malli on yksinkertaisin mahdollinen: työkirjaobjekti jokaista työtä tai työntekijäsäiettä kohden. Tämä mahdollistaa rinnakkaisen raporttien luonnin, johon yksi jaettu Excel-esiintymä ei koskaan pysty. Pyyntökäsittelijä, joka luo, täyttää, tallentaa ja vapauttaa oman työkirjansa, ei tarvitse lukkoja lainkaan, ja virheen vaikutusalue kutistuu tasolta "jaettu Excel-esiintymä on jumissa kaikilta" tasolle "tämä yksittäinen pyyntö heitti poikkeuksen", jonka olemassa oleva virheenkäsittelysi jo osaa käsitellä
Muotokohdistus on viimeinen yksityiskohta. TXLSWorkbook.SaveAs kirjoittaa oletuksena BIFF-muotoa (xlExcel97), ja XLS-sisällön vieminen .xlsx-muotoon kulkee SaveXLSWorkbookAsXLSX-sillan kautta pienemmällä tarkkuudella. Valitse toimitettavaan muotoon sopiva julkisivu jo suunnitteluvaiheessa sen sijaan, että rakennat yhdessä muodossa ja muunnat putken lopussa
Tyypillisen korvausprojektin tietojenlatauspuolta käsittelevät tietokannasta työkirjaan -vientimallit, joissa käydään läpi sekä komponentti että käsin kirjoitettu silmukka, ja kun rivimäärät nousevat kuusinumeroisiksi, suurten työkirjojen suorituskykytekniikat ratkaisevat, kestääkö ajo minuutteja vai sekunteja. Suunnittelijoiden ylläpitämistä asetteluista rakennettuja raportteja käsitellään raporttipohjien luontia käsittelevässä opastuksessa
HotXLS toimitetaan Object Pascal -lähdekoodina Delphille ja C++Builderille; versiot, lisensointi ja koko API-viite ovat HotXLS Delphi Componentin tuotesivulla