Forestil dig et natligt job, der bygger en fakturaprojektmappe i kode og skriver den ud som CSV, så et downstream-system kan importere den. Tallene ser rigtige ud i Excel. CSV-filen åbner problemfrit i en teksteditor. Så går importøren i stå på totalkolonnen, fordi beløbsfeltet for række 42 lyder =SUM(D2:D41), formlen som bogstavelig tekst, ikke det tal, den skulle beregne sig til. Intet er i stykker. Dette er dokumenteret adfærd, og det er det første, man skal forstå om eksport fra HotXLS: skriveren serialiserer cellemodellen præcis som den står, og en formelcelle, hvis værdi aldrig blev beregnet, har kun sin formeltekst at aflevere
Hvorfor din CSV indeholder formler i stedet for tal
HotXLS gemmer formeltekst og beregnet værdi som to adskilte ting. SaveAsCSV kører ikke beregningsmotoren på vej ud, med vilje: en eksport bør ikke ændre projektmappen, og den bør ikke risikere at gå i stå på en patologisk formelkæde. Filer, som Excel selv har gemt, bærer cachede resultater ved siden af formlerne, så det at genexportere dem opfører sig, som man forventer. Fælden er specifik for projektmapper, din egen kode har genereret, hvor formler blev skrevet, men aldrig evalueret. Løsningen er at få værdierne til at eksistere, før du eksporterer, ved brug af den samme Calculate-motor, der løser referencer på tværs af ark og brugerdefinerede funktioner:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
R: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('invoice-run.xlsx');
Sheet := Book.Sheets[0];
// Materialiser formelresultater, så CSV'en bærer tal, ikke '=...'-tekst
for R := 2 to 41 do
if Sheet.Cells[R, 4].Formula <> '' then
Sheet.Cells[R, 4].Value := Book.Calculate(Sheet.Cells[R, 4].Formula);
Book.SaveAsCSV('feed.csv', 0, ','); // ark 0, komma
Book.SaveAsCSV('feed.tsv', 0, #9); // samme ark som TSV
finally
Book.Free;
end;
end;
Læg mærke til, hvad løkken faktisk gør: den overskriver formelcellerne med deres beregnede værdier. Det er helt rigtigt til en engangseksport og forkert, hvis du har tænkt dig at gemme projektmappen som .xlsx bagefter, fordi du netop har erstattet levende formler med frosne tal. Eksportér fra en kopi, eller afgræns tilbageskrivningen, så den kun rammer eksportkørslen. Motoren bag Calculate rækker videre end dette, herunder registrering af dine egne funktioner, hvilket er emnet for HotXLS' formelmotor og brugerdefinerede funktioner
Hvad den afgrænsede skriver garanterer
CSV-stien producerer UTF-8 med en byte order mark, CRLF-linjeskift og RFC 4180-anførsel. Ethvert felt, der indeholder afgrænseren, et anførselstegn eller et linjeskift, bliver pakket ind, og indlejrede anførselstegn fordobles. Datoer gengives som yyyy-mm-dd hh:nn:ss uanset cellens visningsformat. Det er det rigtige valg til en maskinel forbruger, selvom det overrasker enhver, der forventede, at skærmformateringen skulle følge med. Rich text-celler flades ud ved at sammenkæde deres runs
De standardværdier afgør de fleste diskussioner med en importør, før de overhovedet opstår, men to af dem hører alligevel hjemme i din grænsefladekontrakt. Den første er BOM'en. Det er den, der lader Excel åbne filen med accenttegn intakte, men en håndfuld strikse parsere behandler de tre bytes som data; hvis din er en af dem, skal du fjerne dem i overdragelsen. Den anden er TSV. Det er slet ikke en separat funktion, bare den samme skriver kaldt med #9 som afgrænser, så alt ovenfor gælder uændret for den. Det ark, der skal eksporteres, vælges via et 0-baseret indeks i multi-argument-overloadet, mens en-argument-genvejen SaveAsCSV(FileName) tager det aktive ark
HTML-eksport er et øjebliksbillede, ikke et udvekslingsformat
Hvor CSV kasserer alt undtagen værdier, forsøger SaveAsHTML at bevare udseendet: én <table> pr. ark, sammenlagte områder udtrykt som colspan og rowspan, grundlæggende cellestyling indlejret som CSS. Temarelative farver springes over i stedet for at blive opløst, så en skabelon, der læner sig op ad tema-slots, kommer ud mere enkel, end den ser ud i Excel. Sæt eksplicitte RGB-farver på alt, der skal overleve turen. Options-objektet styrer konvolutten:
var
Opts: TXLSXHtmlExportOptions;
begin
Opts := TXLSXHtmlExportOptions.Create;
try
Opts.Title := 'Weekly settlement';
Opts.TableClass := 'report-grid'; // krog til værtssidens stylesheet
Opts.WriteDocument := True; // fuld side, ikke et fragment
if Book.SaveAsHTML('settlement.html', 0, Opts) <> 0 then
raise Exception.Create('Sheet index out of range');
finally
Opts.Free;
end;
end;
To detaljer i det udsnit er værd at bemærke. Sæt WriteDocument til False, og output bliver et nøgent tabelfragment i stedet for en hel side, hvilket er det, du vil have, når du indsætter en forhåndsvisning i et eksisterende layout: sæt TableClass, og lad værtsstylesheetet stå for temaet. Returkonventionen er også modsat de fleste HotXLS-kald. SaveAsHTML returnerer 0 ved succes og -1 ved et ugyldigt arkindeks, så et vanetjek for = 1 vil rapportere hver eneste vellykkede eksport som en fejl. Når du har brug for et område frem for et helt ark, måske for at maile eller indlejre en enkelt blok, eksporterer TXLSXRange.SaveAsHTML ethvert rektangulært område under de samme renderingsregler
RTF-output, og hvor det stadig gør fyldest
Det fjerde mål skriver RTF 1.6-tabeller, ét ark pr. kald via SaveAsRTF. Kolonnebredder tilnærmes til cirka 96 twips pr. tegn kolonnebredde. Den strukturelle begrænsning, man skal kende, er, at sammenlagte celler ikke spænder over i output: kun ankercellen bærer sit indhold, og de dækkede celler udskrives som tomme. Det udelukker RTF til layouttunge skabeloner. Det gør stadig fyldest som vejen med mindst modstand til at droppe tabelresultater ind i en tekstbehandler eller i et gammelt dokumenthåndteringssystem, der går forud for HTML-indlæsning
Rundtur: import af CSV er destruktiv med vilje
At læse CSV tilbage ind har sin egen kontrakt. OpenCSV rydder hele projektmappen og genopbygger den som ét enkelt ark ved navn Sheet1. Den er i ånden en konstruktør, ikke en sammenlægning, så kald den aldrig på en projektmappe, der stadig indeholder ugemt indhold. At angive #0 som separator udløser automatisk registrering af afgrænser. ADetectTypes-flaget styrer typeforfremmelse: med det slået til bliver numeriske strenge til tal, ISO-8601-strenge bliver til datoer, og true/false bliver til booleans. Slå det fra, når feedet bærer identifikatorer med foranstillede nuller, postnumre eller produktkoder, som forfremmelsen alle sammen lydløst forvansker til tal (et foranstillet nul er simpelthen væk, i det øjeblik 00123 bliver til 123). Begge facader eksponerer den samme import. Kombinér den med eksportkaldene ovenfor, og du har en formatbro, der ikke kræver Excel installeret noget sted i pipelinen, scenariet dækket i databaseeksport til Excel-rapporter med HotXLS
Eksport direkte til en stream
Hver skriver her har et stream-overload liggende ved siden af filnavn-versionen: CSV, HTML, RTF og selve projektmappeformaterne. I serverkode er det de overloads, man skal gribe efter. Et webendpoint, der leverer et CSV-download, kan skrive ind i en TMemoryStream og aflevere den direkte til response-objektet, uden midlertidig fil, uden oprydningsjob og uden kollision mellem to forespørgsler, der tilfældigvis valgte samme genererede navn. Det samme gælder, når man skubber eksporter ind i blob-lagring eller vedhæfter dem til udgående mail. Filsystemet forsvinder helt ud af billedet
Det mønster forstærkes af, hvordan biblioteket bliver udrullet. Begge facader er native Object Pascal-læsere og -skrivere, så der er ingen Excel-installation, ingen COM-automatisering og ingen per-proces-flaskehals, der serialiserer forespørgsler på serveren. Hver forespørgsel kan eje sit eget projektmappeobjekt, køre beregnings-tilbageskrivningen fra det første afsnit og streame sin eksport parallelt med sine naboer. Hukommelse er den ene ressource, man skal holde øje med. Projektmappemodellen lever i RAM under hele eksporten, så en tjeneste, der åbner meget store filer bare for at genudsende dem som CSV, bør sætte et loft over samtidige job eller sætte de oversize job i kø frem for at lade en trafikspids afgøre working set'et
En mindre knap: sæt IncludeBOM på HTML-indstillingerne, når fragmentet skal gemmes som en selvstændig fil, som et eller andet værktøj længere nede i kæden sniffer for kodning. Når du leverer HTML direkte over HTTP, skal du i stedet overlade charset-erklæringen til response-headerne
Når bytes stadig kommer forkert ud
Det mest almindelige supportspørgsmål om CSV-eksport er åbningsproblemet i et andet kostume: Excel viser mojibake i stedet for accenttegn. Instinktet er at give skriveren skylden, men den udsender en UTF-8 BOM netop af den grund, og filen er næsten altid korrekt, når den forlader din kode. Noget mellem dér og Excel har spist BOM'en. En FTP-overførsel i tekstmodus, en stream-kopi, der springer de første tre bytes over, en proxy, der genkoder undervejs: enhver af dem vil fjerne markøren og lade Excel gætte på kodningen, hvilket den gør dårligt. Diagnosticér dette ved grænsefladen, ikke i eksportkaldet. Åbn den leverede fil i en hex-viewer, og bekræft at EF BB BF stadig er det første i den
Det er den røde tråd for alle fire formater. Eksportkaldet er den lette del, og HotXLS træffer et forsvarligt valg ved hver beslutning, skriveren står over for. Fejlene bor i samlingerne, hvor formeltekst møder en parser, der ville have et tal, hvor en BOM møder en transport, der ikke bevarer den, hvor en sammenlagt celle møder RTF's flade tabelmodel. Hver af dem er et faktum, der skal skrives ind i kontrakten mellem din eksportør og hvad end der forbruger den, fordi forbrugeren ikke kan læse dine hensigter ud af bytes. For den fulde metodeliste på tværs af begge projektmappefacader bærer produktsiden for HotXLS-Delphi-komponenten den fulde reference