Kadang satu-satunya pertanyaan yang perlu dijawab sebuah rutin intake bersifat struktural: apakah workbook ini punya sheet bernama "Mapping", atau berapa banyak tab yang dibawanya. Menjawab itu dengan memanggil Open adalah cara yang mahal untuk melakukannya. Open penuh menggembungkan shared string table, mendekode setiap record style, dan menyusuri sel-sel di setiap worksheet, karena ia tidak punya cara untuk tahu bahwa Anda hanya menginginkan daftar isi. Pada file besar itu berarti ratusan megabyte alokasi memori dan beberapa detik CPU dihabiskan hanya untuk membaca sebuah daftar yang menempati beberapa kilobyte saja. HotXLS, pustaka spreadsheet native Delphi dari losLab, memberikan daftar itu tersendiri: GetSheetNames mengembalikan nama-nama worksheet, sesuai urutan dalam workbook, tanpa mewujudkan satu sel pun
Mengapa Katalognya Murah untuk Dibaca
Kedua format spreadsheet menaruh daftar isinya di dekat bagian depan, dan itulah yang membuat panggilan listing cepat, bukan karena kepintaran tertentu. Paket OOXML menyimpan katalog sheet di xl/workbook.xml, sebuah bagian yang tetap kecil baik workbook itu memuat sepuluh baris maupun sepuluh juta baris. File BIFF8 .xls menyimpan record BoundSheet-nya di awal stream globals workbook, sebelum data sel apa pun. Jadi pekerjaan yang dihindari oleh panggilan listing bukan sekadar pembulatan kecil dibandingkan open penuh. Itu adalah sebagian besar dari file itu sendiri. Membaca katalog menghabiskan biaya yang sama, hanya beberapa kilobyte, berapa pun jumlah barisnya, sementara open penuh berskala mengikuti data, dan pada workbook berukuran puluhan megabyte kesenjangan itu mencapai beberapa orde besaran, baik dari sisi byte yang disentuh maupun memori yang dialokasikan
Biaya yang datar itulah properti yang layak dijadikan dasar desain. Sebuah gerbang intake yang dibangun di atas GetSheetNames berperilaku sama pada file 200 baris maupun file 200 MB, sehingga file paling lambat dalam sebuah batch tidak lagi menentukan kecepatan untuk memutuskan apakah sebuah file layak diproses sama sekali
Satu Panggilan untuk .xls, .xlsx, dan Format Template
Pada facade XLS, TXLSWorkbook.GetSheetNames membaca lebih dari sekadar .xls. Ia juga menerima format berbasis zip .xlsx, .xlsm, .xltx, dan .xltm, hanya menarik workbook.xml dari arsipnya. Untuk input .xls sejati, ia memindai record BoundSheet dan berhenti pada record EOF pertama dari substream globals, sehingga file biner besar tetap hanya menghabiskan biaya beberapa kilobyte pembukanya. Facade XLSX membawa sebuah jaminan yang lebih penting bagi kode layanan yang berjalan lama daripada yang terlihat sekilas: TXLSXWorkbook.GetSheetNames tidak mereset maupun mengisi instance workbook, sehingga instance yang sudah memegang dokumen terbuka bisa memeriksa file lain tanpa mengganggu file yang sedang dipegangnya. GetODSSheetNames menerapkan pendekatan yang sama pada paket OpenDocument, dan setiap panggilan ini punya overload stream, yang memungkinkan Anda memeriksa upload yang tidak pernah mendarat di disk
var
Book: TXLSXWorkbook;
Names: TStringList;
I: Integer;
begin
Names := TStringList.Create;
Book := TXLSXWorkbook.Create;
try
if Book.GetSheetNames('upload-7f3a.xlsx', Names) <= 0 then
raise Exception.Create('unreadable workbook package');
if Names.IndexOf('Mapping') < 0 then
raise Exception.Create('required Mapping sheet is missing');
for I := 0 to Names.Count - 1 do
Writeln(Format('sheet %d: %s', [I, Names[I]]));
finally
Book.Free;
Names.Free;
end;
end;
Panggilan yang sama juga cocok untuk dialog import di aplikasi desktop. Daftar sheet-nya, biarkan pengguna memilih satu, dan baru bayar biaya open penuh setelah pilihan dibuat. Dengan workbook lima puluh sheet, perbedaannya terlihat jelas: picker yang muncul seketika dibandingkan yang macet sementara seluruh file dimuat di baliknya
File .xlsm yang mengaktifkan makro dan format template terdaftar persis seperti .xlsx biasa, karena katalognya berada di workbook.xml yang sama, baik ada vbaProject.bin yang ikut serta dalam paket maupun tidak. Sebuah pipeline intake karena itu bisa mendaftar sheet dari sebuah workbook bermakro untuk keperluan routing, tanpa pernah menyentuh payload makronya dan tanpa pernah melakukan apa pun yang bisa menjalankannya, dan menyerahkan keputusan kebijakan makro kepada tahap yang benar-benar membuka file tersebut
Membaca Nilai Kembalian Tanpa Menipu Diri Sendiri
Konvensi nilai kembalian tidak seragam di seluruh HotXLS. Sebagian panggilan mengembalikan 1 saat berhasil, sebagian lain mengembalikan sebuah count, sehingga untuk fungsi-fungsi listing, satu-satunya pemeriksaan yang benar-benar bisa diandalkan adalah memperlakukan nilai nol atau di bawahnya sebagai kegagalan, dengan string list yang sudah dikosongkan. Tahan godaan untuk membaca daftar kosong sebagai "workbook tanpa sheet." Baik ECMA-376 maupun spesifikasi BIFF8 mensyaratkan minimal satu sheet dalam workbook yang valid, sehingga nol nama selalu berarti pembacaannya gagal, tidak pernah berarti filenya memang kosong secara sah
Sebuah listing yang gagal itu sendiri adalah sinyal yang layak disimpan. File .xlsx yang gagal pada panggilan tersebut biasanya salah satu dari beberapa hal spesifik: terpotong, sebenarnya bukan paket OOXML sama sekali (ekspor CSV yang diberi label salah dari sistem lain terus-menerus muncul di sini), atau kontainer terenkripsi. Membedakan ketiganya adalah tugas pemeriksaan berikutnya. Mencatat byte-byte pertama dari file yang ditolak bersama kegagalannya biasanya mengubah sebuah thread support menjadi hanya satu pesan saja
Mendeteksi Kontainer Terenkripsi Sebelum Melakukan Routing
File .xlsx terenkripsi bukanlah sebuah zip. Ia adalah file compound OLE yang membungkus stream EncryptionInfo dan EncryptedPackage, sehingga GetSheetNames tidak bisa melihat ke dalamnya dan mengembalikan kegagalan seperti file tak terbaca lainnya. CanReadEncrypted menguji bentuk kontainer semacam itu, yang memungkinkan intake melakukan routing file terenkripsi secara sengaja, alih-alih menelan begitu saja sebuah error baca generik dari suatu tempat jauh di dalam worker:
type
TIntakeRoute = (irNormal, irNeedsPassword, irUnreadable);
function ClassifyUpload(const FileName: string; Names: TStrings): TIntakeRoute;
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// OOXML terenkripsi adalah kontainer OLE, bukan zip: periksa dulu,
// karena panggilan listing tidak bisa melihat ke dalamnya.
if Book.CanReadEncrypted(FileName) then
Exit(irNeedsPassword);
if SameText(ExtractFileExt(FileName), '.ods') then
begin
if Book.GetODSSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
end
else if Book.GetSheetNames(FileName, Names) <= 0 then
Exit(irUnreadable);
Result := irNormal;
finally
Book.Free;
end;
end;
Enkripsi adalah area di mana HotXLS sengaja dibuat asimetris, sehingga routing-nya harus menghormati hal itu. Enkripsi .xls lawas (RC4, RC4 CryptoAPI, XOR) bisa dibaca: TXLSWorkbook.Open(FileName, Password) mendekripsi dengan password yang tersimpan, dan file-file itu bisa tetap berada di jalur otomatis. Paket OOXML terenkripsi berjalan ke arah sebaliknya. HotXLS bisa menulis satu dengan SaveAsEncrypted, tetapi tidak bisa membacanya kembali. OpenEncrypted memunculkan EXlsxEncryptionNotImplemented ketika diberi sebuah paket terenkripsi, itulah sebabnya desain intake yang jujur mengirim .xlsx terenkripsi kepada seseorang dengan Excel dan menjaga .xls berpassword tetap ditangani dalam kode
Untuk pekerjaan batch, classifier ini sepadan tempatnya dengan berjalan melalui seluruh direktori yang masuk sebelum satu pun worker mulai pemrosesan sungguhan, karena setiap probe hanya menghabiskan biaya kira-kira satu kali open file dan beberapa kilobyte pembacaan. Menaruhnya di depan mengubah mode kegagalan yang sebenarnya diperhatikan oleh tim operasional. Alih-alih sebuah job jam 3 pagi mati di file 412 dari 600, Anda mendapatkan 412 file yang antre dan 5 yang ditolak saat intake dengan alasan yang melekat pada masing-masing. Panggilan pustaka yang sama, cerita operasional yang jauh lebih baik
Pertanyaan yang Tidak Bisa Dijawab oleh Panggilan Listing
Nama dan urutan adalah keseluruhan dari apa yang Anda dapatkan. Panggilan listing tidak mengatakan apa pun soal visibilitas, sehingga sheet yang hidden dan very-hidden tetap muncul di daftar seolah sama seperti yang lain. Panggilan ini tidak melaporkan dimensi used-range, jumlah sel, maupun properti dokumen. Bagian docProps/core.xml juga berukuran kecil, tetapi hingga saat ini belum ada probe khusus properti saja, sehingga metadata author dan title tetap membutuhkan Open penuh. Cara bersih untuk hidup dengan kenyataan itu adalah membiarkan fakta-fakta yang murah melakukan routing untuk setiap file, dan menyisakan yang mahal hanya untuk file yang lolos routing. Untuk file yang memang berlanjut ke pembacaan mendalam, pemindaian read-only pada .xls besar berjalan jauh lebih cepat dengan _DisableGraphics := True, yang melewati parsing OfficeArt. Hanya saja jangan pernah menyimpan dari instance itu: lapisan gambar yang dilewatkannya telah hilang dari model, dan penyimpanan akan membuangnya dari file
File yang lolos triase biasanya berlanjut ke analisis yang lebih mendalam. Workbench audit dan konversi workbook membahas counter per-sheet yang layak dikumpulkan begitu open penuh memang beralasan, dan panduan performa workbook besar membahas cara menjaga open penuh itu tetap cepat
HotXLS adalah pustaka spreadsheet Object Pascal native untuk Delphi dan C++Builder; seluruh permukaan API-nya, termasuk panggilan inspeksi yang ditunjukkan di sini, didokumentasikan di halaman produk HotXLS Delphi Component