Bayangkan sebuah job malam hari yang membangun sebuah workbook invoice dalam kode dan menulisnya keluar sebagai CSV untuk diimpor sistem downstream. Angka-angkanya terlihat benar di Excel. File CSV-nya terbuka dengan bersih di text editor. Lalu importer-nya tersedak pada kolom total, karena field amount untuk baris 42 berbunyi =SUM(D2:D41), formulanya sebagai teks literal, bukan angka yang seharusnya ia hasilkan. Tidak ada yang rusak. Ini adalah perilaku yang terdokumentasi, dan inilah hal pertama yang perlu dipahami tentang ekspor dari HotXLS: writer-nya menyerialisasi cell model persis sebagaimana adanya, dan sebuah cell formula yang nilainya tidak pernah dihitung hanya punya teks formulanya sendiri untuk diserahkan
Mengapa CSV Anda berisi formula, bukan angka
HotXLS menyimpan teks formula dan nilai hasil hitungnya sebagai dua hal yang terpisah. SaveAsCSV tidak menjalankan calculation engine saat mengeluarkan datanya, dan itu memang disengaja: sebuah ekspor seharusnya tidak mengubah workbook, dan seharusnya tidak berisiko macet pada sebuah rantai formula yang patologis. File yang disimpan langsung oleh Excel membawa hasil yang di-cache di samping formulanya, sehingga mengekspor ulang file semacam itu berperilaku sesuai harapan Anda. Jebakannya spesifik untuk workbook yang dihasilkan oleh kode Anda sendiri, tempat formula ditulis namun tidak pernah dievaluasi. Solusinya adalah membuat nilai-nilai itu ada sebelum Anda mengekspor, menggunakan engine Calculate yang sama yang menyelesaikan referensi lintas-sheet dan fungsi kustom:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
R: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('invoice-run.xlsx');
Sheet := Book.Sheets[0];
// Materialisasikan hasil formula agar CSV membawa angka, bukan teks '=...'
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, ','); // sheet 0, koma
Book.SaveAsCSV('feed.tsv', 0, #9); // sheet sama sebagai TSV
finally
Book.Free;
end;
end;
Perhatikan apa yang sebenarnya dilakukan loop ini: ia menimpa cell formula dengan nilai hasil hitungnya. Itu persis benar untuk sebuah lintasan ekspor sekali-pakai dan salah jika Anda bermaksud menyimpan kembali workbook itu sebagai .xlsx setelahnya, karena Anda baru saja mengganti formula hidup dengan angka beku. Ekspor dari sebuah salinan, atau batasi write-back tersebut sehingga hanya menyentuh jalannya ekspor. Engine di balik Calculate melangkah lebih jauh dari ini, termasuk mendaftarkan fungsi kustom Anda sendiri, yang menjadi pokok bahasan formula engine dan fungsi kustom HotXLS
Apa yang dijamin oleh writer berpembatas
Jalur CSV menghasilkan UTF-8 dengan sebuah byte order mark, akhir baris CRLF, dan penguotean RFC 4180. Field mana pun yang mengandung delimiter, sebuah tanda kutip, atau sebuah pemutus baris akan dibungkus, dan tanda kutip yang tertanam digandakan. Tanggal dirender sebagai yyyy-mm-dd hh:nn:ss terlepas dari format tampilan cell-nya. Itu keputusan yang tepat untuk sebuah konsumen mesin, meski hal itu mengejutkan siapa pun yang berharap formatting di layar akan ikut terbawa. Cell rich text diratakan dengan menggabungkan run-runnya
Default-default itu menuntaskan sebagian besar perdebatan dengan sebuah importer sebelum perdebatan itu dimulai, tetapi dua di antaranya tetap layak masuk ke dalam kontrak antarmuka Anda. Yang pertama adalah BOM. Itulah yang membuat Excel bisa membuka file dengan karakter beraksen tetap utuh, namun segelintir parser yang ketat memperlakukan tiga byte itu sebagai data; jika parser Anda salah satunya, buang byte itu saat serah terima. Yang kedua adalah TSV. Ini sama sekali bukan fitur terpisah, hanya writer yang sama dipanggil dengan #9 sebagai delimiter, sehingga semua yang dijelaskan di atas berlaku untuknya tanpa perubahan. Sheet yang akan diekspor dipilih melalui indeks berbasis 0 pada overload multi-argumen, sementara singkatan argumen tunggal SaveAsCSV(FileName) mengambil sheet yang sedang aktif
Ekspor HTML adalah sebuah snapshot, bukan format pertukaran
Di mana CSV membuang semuanya kecuali nilai, SaveAsHTML berusaha mempertahankan tampilannya: satu <table> per sheet, region gabungan dinyatakan sebagai colspan dan rowspan, styling cell dasar disisipkan inline sebagai CSS. Warna yang relatif terhadap theme dilewati begitu saja alih-alih diselesaikan, sehingga sebuah template yang mengandalkan slot theme keluar lebih polos daripada tampilannya di Excel. Tetapkan warna RGB eksplisit pada apa pun yang harus bertahan melewati perjalanan ini. Objek options mengendalikan amplopnya:
var
Opts: TXLSXHtmlExportOptions;
begin
Opts := TXLSXHtmlExportOptions.Create;
try
Opts.Title := 'Weekly settlement';
Opts.TableClass := 'report-grid'; // hook untuk stylesheet halaman host
Opts.WriteDocument := True; // halaman penuh, bukan sebuah fragment
if Book.SaveAsHTML('settlement.html', 0, Opts) <> 0 then
raise Exception.Create('Sheet index out of range');
finally
Opts.Free;
end;
end;
Dua detail dalam cuplikan itu layak diperhatikan. Ubah WriteDocument menjadi False dan outputnya menjadi sebuah fragment table telanjang alih-alih halaman penuh, yang justru Anda inginkan saat menyuntikkan sebuah preview ke dalam layout yang sudah ada: tetapkan TableClass dan biarkan stylesheet host yang mengurus tema. Konvensi nilai baliknya juga kebalikan dari kebanyakan pemanggilan HotXLS lain. SaveAsHTML mengembalikan 0 saat berhasil dan -1 untuk indeks sheet yang tidak valid, sehingga sebuah pemeriksaan yang terbiasa mencari = 1 akan melaporkan setiap ekspor yang berhasil sebagai kegagalan. Ketika Anda butuh sebuah region, bukan seluruh sheet, mungkin untuk dikirim lewat email atau ditanamkan sebagai satu blok tunggal, TXLSXRange.SaveAsHTML mengekspor range persegi panjang mana pun di bawah aturan rendering yang sama
Output RTF dan di mana ia masih layak digunakan
Target keempat menulis tabel RTF 1.6, satu sheet per pemanggilan lewat SaveAsRTF. Lebar kolom didekati pada kira-kira 96 twip per karakter lebar kolom. Batasan struktural yang perlu diketahui adalah bahwa cell gabungan tidak membentang dalam output: hanya cell anchor yang membawa kontennya, dan cell yang tertutupi terpancar sebagai kosong. Itu menyingkirkan RTF sebagai pilihan untuk template yang berat pada layout. RTF tetap layak digunakan sebagai jalur dengan hambatan paling kecil untuk menaruh hasil tabular ke dalam word processor atau ke dalam sebuah sistem manajemen dokumen lawas yang lebih tua dari era HTML
Round-trip: mengimpor CSV bersifat destruktif secara desain
Membaca kembali CSV memiliki kontraknya sendiri. OpenCSV mengosongkan seluruh workbook dan membangunnya kembali sebagai satu sheet tunggal bernama Sheet1. Ini secara jiwa adalah sebuah constructor, bukan sebuah merge, sehingga jangan pernah memanggilnya pada sebuah workbook yang masih menyimpan konten yang belum disimpan. Mengoper #0 sebagai separator memicu deteksi delimiter otomatis. Flag ADetectTypes mengendalikan promosi tipe: ketika diaktifkan, string numerik menjadi angka, string ISO-8601 menjadi tanggal, dan true/false menjadi boolean. Matikan flag itu ketika feed membawa identifier dengan angka nol di depan, kode pos, atau kode produk, yang semuanya diam-diam dirusak promosi ini menjadi angka (sebuah nol di depan begitu saja hilang saat 00123 menjadi 123). Kedua facade mengekspos import yang sama. Pasangkan dengan pemanggilan ekspor di atas, dan Anda mendapatkan sebuah jembatan format yang tidak membutuhkan Excel terpasang di mana pun dalam pipeline, skenario yang dibahas dalam pembuatan laporan Excel dari database dengan HotXLS
Mengekspor langsung ke dalam sebuah stream
Setiap writer di sini punya sebuah overload stream yang berdampingan dengan versi nama-filenya: CSV, HTML, RTF, dan format workbook itu sendiri. Dalam kode server, overload itulah yang perlu digunakan. Sebuah web endpoint yang menyajikan unduhan CSV bisa menulis ke dalam sebuah TMemoryStream dan menyerahkannya langsung ke objek response, tanpa file sementara, tanpa job pembersihan, dan tanpa tabrakan antara dua request yang kebetulan memilih nama yang dihasilkan sama. Hal yang sama berlaku untuk mendorong ekspor ke dalam blob storage atau melampirkannya ke email keluar. Sistem file sepenuhnya lenyap dari gambaran ini
Pola itu berlipat ganda manfaatnya dengan cara library ini di-deploy. Kedua facade adalah reader dan writer Object Pascal native, sehingga tidak ada instalasi Excel, tidak ada COM automation, dan tidak ada bottleneck per-proses yang menyerialisasi request di server. Setiap request bisa memiliki objek workbook-nya sendiri, menjalankan write-back kalkulasi dari bagian pertama, dan mengalirkan ekspornya secara paralel dengan request tetangganya. Memori adalah satu-satunya sumber daya yang perlu terus diawasi. Model workbook tinggal di RAM selama durasi ekspor, sehingga sebuah layanan yang membuka file yang sangat besar hanya untuk memancarkannya ulang sebagai CSV sebaiknya membatasi jumlah job yang berjalan bersamaan, atau mengantrekan yang berukuran berlebih, alih-alih membiarkan lonjakan traffic yang menentukan working set-nya
Satu tuas yang lebih kecil: setel IncludeBOM pada opsi HTML ketika fragment itu akan disimpan sebagai sebuah file mandiri yang diendus encoding-nya oleh sebuah tool downstream. Ketika Anda menyajikan HTML langsung lewat HTTP, serahkan saja deklarasi charset-nya kepada header response
Ketika byte-nya masih saja keluar salah
Pertanyaan dukungan yang paling umum tentang ekspor CSV adalah masalah pembuka artikel ini dalam kostum berbeda: Excel menampilkan mojibake alih-alih karakter beraksen. Insting pertama adalah menyalahkan writer-nya, tetapi writer itu memancarkan sebuah UTF-8 BOM persis untuk alasan ini, dan file itu hampir selalu benar saat meninggalkan kode Anda. Ada sesuatu di antara titik itu dan Excel yang memakan BOM-nya. Sebuah transfer FTP dalam mode teks, sebuah stream copy yang melewatkan tiga byte pertama, sebuah proxy yang meng-encode ulang saat lewat: mana pun dari itu akan melepas penanda tersebut dan membiarkan Excel menebak-nebak encoding-nya, yang ia lakukan dengan buruk. Diagnosis hal ini di batasnya, bukan pada pemanggilan ekspor. Buka file yang terkirim itu dalam sebuah hex viewer dan pastikan EF BB BF masih menjadi hal pertama di dalamnya
Itulah benang merah untuk keempat format ini. Pemanggilan ekspornya adalah bagian yang mudah, dan HotXLS membuat pilihan yang bisa dipertanggungjawabkan pada setiap keputusan yang dihadapi writer-nya. Kegagalan justru tinggal di sambungan-sambungannya, tempat teks formula bertemu sebuah parser yang menginginkan sebuah angka, tempat sebuah BOM bertemu sebuah transport yang tidak mempertahankannya, tempat sebuah cell gabungan bertemu model tabel datar milik RTF. Masing-masing dari itu adalah sebuah fakta yang perlu dituliskan ke dalam kontrak antara exporter Anda dan apa pun yang mengonsumsinya, karena konsumen tidak bisa membaca maksud Anda dari byte-nya saja. Untuk daftar method lengkap di kedua facade workbook, halaman produk HotXLS Delphi Component memuat referensi selengkapnya