fix(export): enable ZIP64 for large XLSX exports

This commit is contained in:
zipg
2026-09-14 22:26:38 +08:00
committed by GitHub
parent 8240df143a
commit c6ecd9808f
+19 -2
View File
@@ -238,7 +238,10 @@ fn push_data_row_xml(
/// `inlineStr` cell encoding is highly repetitive, so Deflate typically shrinks
/// the file several-fold over `Stored` (matching what Excel/Navicat produce).
fn xlsx_zip_options() -> zip::write::SimpleFileOptions {
zip::write::SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated)
// Table exports can exceed the ZIP32 4 GiB entry limit even when the
// result is streamed row by row. Enable ZIP64 up front so the writer does
// not fail after a long export has already queried the database.
zip::write::SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated).large_file(true)
}
fn write_zip_entry<W: Write + Seek>(zip: &mut zip::ZipWriter<W>, path: &str, content: &str) -> Result<(), String> {
@@ -1226,7 +1229,7 @@ mod tests {
use calamine::{open_workbook_auto, Reader};
use serde_json::{json, Value};
use std::fs;
use std::io::{Read, Write};
use std::io::{Cursor, Read, Write};
#[derive(Default)]
struct WriteStats {
@@ -1257,6 +1260,20 @@ mod tests {
content
}
#[test]
fn xlsx_zip_entries_enable_zip64_for_large_exports() {
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
zip.start_file("large-entry.xml", super::xlsx_zip_options()).expect("start ZIP64 entry");
zip.write_all(b"test").expect("write ZIP64 entry");
let bytes = zip.finish().expect("finish ZIP64 archive").into_inner();
assert_eq!(&bytes[..4], b"PK\x03\x04");
let name_len = u16::from_le_bytes([bytes[26], bytes[27]]) as usize;
let extra_len = u16::from_le_bytes([bytes[28], bytes[29]]) as usize;
let extra_data = &bytes[30 + name_len..30 + name_len + extra_len];
assert!(extra_data.windows(2).any(|tag| tag == [0x01, 0x00]));
}
/// Assert every entry in the XLSX (ZIP) buffer is Deflate-compressed, which
/// is what keeps exported workbooks small (see `xlsx_zip_options`).
fn assert_all_entries_deflated(bytes: &[u8]) {