Bài viết kỹ thuật

Lưu trữ ô theo khối dòng và lưu XLSX streaming trong HotXLS

HotXLS lưu ô trang tính trong các khối 256 dòng compact, giải quyết định dạng dòng, cột và hình chữ nhật thông qua overlay khoảng lười thay vì tạo object ô, và stream từng dòng thẳng vào deflate stream của package khi lưu. Cùng nhau ba thay đổi đó quyết định hồ sơ bộ nhớ của một sổ làm việc lớn: mức dùng đỉnh theo dõi dòng đơn lớn nhất thay vì kích thước XML trang tính hoàn chỉnh

Lý do điều này quan trọng là một hình dạng mà mọi nhà phát triển bảng tính cuối cùng đều gặp. Một người dùng định dạng toàn bộ một cột — một nhấp, một triệu ô — và một object model ngây ngô đáp lại bằng cách cấp phát một triệu object ô để giữ một chỉ mục number-format. File trên đĩa vẫn nhỏ vì định dạng XLSX diễn tả điều đó như một mục <col> duy nhất. Tiến trình thì không hề nhỏ chút nào

Vì sao định dạng một cột lại tốn bộ nhớ hơn điền đầy nó?

Vì định dạng không có dữ liệu để biện minh cho object. Một ô có giá trị phải tồn tại ở đâu đó. Một ô rỗng nhưng có style chỉ tồn tại để mang một style index, và hiện thực hóa hàng triệu cái như vậy là cách kinh điển khiến một ứng dụng bảng tính Delphi cạn không gian địa chỉ trên một file mà Excel mở tức thì

Overlay khoảng style loại bỏ nhu cầu đó. Một chỉ dẫn định dạng dòng, cột hoặc hình chữ nhật được lưu một lần dưới dạng một khoảng cộng với các phần style nó đóng góp, và giải quyết lười khi một ô trong khoảng đó thực sự được truy cập. Overlay sống sót qua các sửa đổi cấu trúc — chèn một dòng vào trong một khối đã định dạng sẽ dịch khoảng thay vì dựng lại — và chúng vòng chuyến dưới dạng các mục cột, dòng và ô chỉ-style compact, đó chính xác là cách Excel ghi chúng

Sơ đồ phủ style theo khoảng cho HotXLS cho thấy một dải định dạng cột được lưu thành một record với các phần định dạng được tuyên bố thay vì một triệu đối tượng ô rỗng trong Delphi
Một format cột, hàng hoặc hình chữ nhật tồn tại đúng một lần như record overlay dạng khoảng chỉ tuyên bố sở hữu phần của nó. Style hiệu dụng được lắp ráp lười ngay lần đầu một ô bên trong vùng thực sự bị chạm tới
var
  Sheet: TXLSXWorksheet;
  State: TXLSXCellStyleState;
begin
  Sheet := Workbook.Sheets[1];
  //  Các chỉ số kiểu đến từ các nhóm kiểu của workbook, ví dụ từ một ô
  //  bạn đã định dạng theo cách bạn muốn phạm vi trông ra sao
  State := BuildStateFromTemplateCell(Sheet.Cells.Item[1, 1]);
  //  Định dạng các cột B..D mà không tạo bất kỳ một đối tượng ô trống nào
  Sheet.StyleOverlays.Add(1, 2, MaxRowIndex, 4,
    [xfpNumberFormat, xfpAlignment], State);
end;

TXLSXFormatParts là tập hợp quyết định một overlay đóng góp gì: xfpFont, xfpFill, xfpBorder, xfpNumberFormat, xfpAlignment và xfpProtection. Chỉ nêu tên những phần bạn định nghĩa là điều khiến overlay xếp lớp hợp lý — một overlay cột cung cấp number format không xung đột với một overlay dòng cung cấp fill, vì không bên nào tuyên bố sở hữu phần của bên kia

Khối 256 dòng mang lại cho bạn điều gì

Tính cục bộ. Ô được giữ trong các khối 256 dòng với handle công khai ổn định, tuần tự hóa theo hàng, nên ghi một trang tính duyệt bộ nhớ theo thứ tự nó sẽ phát byte thay vì đuổi theo con trỏ khắp heap. Handle ổn định quan trọng cho bề mặt API: một handle mà bên gọi giữ vẫn hợp lệ qua việc tái tổ chức nội bộ mà bố cục khối thực hiện, đó là điều khiến biểu diễn compact trở thành chi tiết hiện thực thay vì một thay đổi phá vỡ

Sơ đồ lưu trữ khối hàng cho thấy các ô worksheet HotXLS được giữ trong các khối cố định 256 hàng với các handle Delphi ổn định và serialize ưu-tên-hàng vào stream deflate XLSX
Các ô nằm trong những khối cố định 256 hàng chỉ cấp phát các hàng có dữ liệu và serialize theo đúng thứ tự byte rời tiến trình. Handle công khai sống sót qua việc tổ chức lại nội bộ, nên bố cục khối vẫn vô hình với caller

Nén style pool chạy cùng với nó. Trước mỗi lần lưu, font, fill, border, number format, alignment và protection mà không ô nào tham chiếu sẽ bị loại bỏ. Sổ làm việc tồn tại lâu tích lũy bản ghi style không tham chiếu giống như tài liệu tồn tại lâu tích lũy style không dùng, và một sổ làm việc đã được người dùng chỉnh sửa một tiếng có thể mang hàng trăm cái như vậy vào một file mà không ai sẽ đọc chúng ra bao giờ

Lưu streaming theo dòng, và khi nào nó không áp dụng

Với StreamingWrite bật — mặc định — mỗi dòng trang tính được ghi trực tiếp vào deflate stream của package. Phương án thay thế, đó là cái cờ tắt, dựng XML trang tính hoàn chỉnh trước rồi nén sau, nên bộ nhớ đỉnh tỉ lệ với cả trang. Streaming khiến nó tỉ lệ với một dòng

Shared string và các part phụ trợ theo cùng kỷ luật qua một serializer UTF-8 tái sử dụng được phát ra từng mục một, giới hạn bộ nhớ đỉnh bởi mục đơn lớn nhất thay vì cả part. Điều đó bao phủ bảng shared string và bản ghi pivot, vốn trên một sổ làm việc phân tích rộng thường lớn hơn bất kỳ trang tính đơn lẻ nào

var
  Workbook: TXLSXWorkbook;
begin
  Workbook := TXLSXWorkbook.Create;
  try
    Workbook.Open('ledger-2026.xlsx');
    //  StreamingWrite mặc định là True; chỉ tắt nó khi một bước
    //  phía sau yêu cầu toàn bộ XML của trang tính tồn tại trước khi nén
    Workbook.StreamingWrite := True;
    Workbook.SaveAs('ledger-2026-out.xlsx');
  finally
    Workbook.Free;
  end;
end;

Hãy để nó bật trừ khi bạn có lý do cụ thể để tắt. Đường không streaming tồn tại cho các trường hợp nơi thứ gì khác trong pipeline cần XML lắp ráp, và trả giá cho nó theo mặc định là trả giá cho một trường hợp mà hầu hết ứng dụng không bao giờ gặp

Làm sao biết overlay có thực sự được dùng?

Theo dõi số ô, không phải đồ thị bộ nhớ. Nếu một trang tính báo một số ô vật lý hợp lý sau khi bạn áp dụng định dạng rộng, overlay đang làm việc. Nếu số nhảy theo kích thước khoảng đã định dạng, có thứ gì đó trong đường dẫn mã đã hiện thực các ô — thường là một vòng lặp đọc mọi ô trong khoảng để kiểm tra style, điều ép giải pháp từng ô một và đánh bại toàn bộ sắp đặt

Sơ đồ StreamingWrite so sánh deflate streaming theo từng hàng trong HotXLS với cách lắp toàn bộ XML worksheet trong bộ nhớ trước khi nén trong Delphi
Khi StreamingWrite bật, mỗi hàng chảy thẳng vào deflate stream của package và bộ nhớ đỉnh bám theo một hàng. Tắt cờ này sẽ lắp ráp trước toàn bộ XML worksheet, khiến bộ nhớ đỉnh tăng theo cả trang tính

Giải một style khi bạn cần định dạng hiệu dụng của một ô. Đừng giải style cho một triệu ô chỉ để biết cột có một number format; hãy hỏi overlay. Cùng quy tắc áp dụng cho việc ghi: gán giá trị cho các ô có giá trị, và để định dạng vẫn là một khoảng

Nơi bộ nhớ còn lại đi về đâu

Một khi ô và style đã compact, những bên tiêu thụ lớn kế tiếp trên một sổ làm việc lớn là bảng shared string và các part vệ tinh mà file mang theo — pivot cache, drawing, XML bảo toàn từ các part mà object model không model. Mỗi cái có chiến lược riêng, và câu trả lời trung thực là không có thiết lập đơn lẻ nào giải quyết tất cả cùng lúc

Nếu nút cổ chai của bạn là mở thay vì lưu, tải chọn lọc là đòn bẩy: bài viết về tải trang tính metadata-only và chọn lọc trình bày việc đọc một sổ làm việc mà không trả giá cho các trang bạn sẽ không chạm tới. Đối với throughput đường đọc trên các file rất lớn, xem các ghi chú về phân tích XLSX song song và bộ cấp phát bộ nhớ, còn với khối công việc chỉ xuất mà không bao giờ cần object model, ghi streaming cho tác vụ hàng loạt máy chủ thường phù hợp hơn bất kỳ lượng tinh chỉnh nào ở đây

HotXLS đọc và ghi XLS và XLSX từ mã Delphi và C++Builder bản địa không cần cài Excel và không OLE automation, đó là điều khiến các đặc tính bộ nhớ này quan sát được và kiểm soát được ngay từ đầu — trang thành phần bảng tính HotXLS liệt kê các định dạng và phiên bản RAD Studio được hỗ trợ