HotXLS สามารถเขียนเวิร์กชีตหนึ่งแผ่นในแพ็กเกจ XLSX ที่มีอยู่แล้วใหม่ได้ โดยไม่ต้องแยกวิเคราะห์หรือบีบอัดส่วนที่เหลือของไฟล์ใหม่ TXLSDirectWriter.BeginPatch เปิดแพ็กเกจต้นทาง คัดลอกทุกรายการยกเว้นชีตเป้าหมายข้ามไปพร้อมไบต์ที่บีบอัดแล้วแบบคำต่อคำ และให้คุณเขียนชีตแผ่นเดียวนั้นใหม่ผ่านการเรียก AddSheet, AddRow และ Write* ตามปกติ แผนภูมิ แคช pivot ธีม สไตล์ และสตริงที่ใช้ร่วมกันจะไม่ถูกคลายการบีบอัดเลยแม้แต่น้อย
เวิร์กโฟลว์ที่ปัญหานี้แก้ไขให้ปรากฏในงานรายงานและการรีเฟรชข้อมูล สมุดงานหนึ่งมาจากทีมธุรกิจซึ่งพกตาราง pivot สไลเซอร์ รูปแบบมีเงื่อนไข และการจัดรูปแบบที่สะสมมาสิบปี ทุกคืนต้องแทนที่ชีตข้อมูลหนึ่งแผ่นด้วยตัวเลขใหม่ การโหลดและบันทึกสมุดงานทั้งเล่มใหม่มีต้นทุนหลายนาทีต่อไฟล์ และที่สำคัญกว่านั้นคือเสี่ยงต่อความเที่ยงตรงของคุณสมบัติที่เอนจินโหลดต้องสร้างขึ้นใหม่ การแพตช์หลีกเลี่ยงปัญหาทั้งสองอย่างด้วยการไม่แตะต้องสิ่งที่ไม่จำเป็นต้องแตะต้อง
เหตุใดการคัดลอกไบต์ที่บีบอัดแล้วจึงเป็นส่วนที่น่าสนใจ
รายการ zip ที่ถูกคัดลอกในระดับที่บีบอัดแล้วมีต้นทุนเป็นเพียงการคัดลอกสตรีม รายการเดียวกันที่ผ่านเส้นทางเขียนปกติมีต้นทุนเป็นการคลายการบีบอัดตอนเข้าและบีบอัดตอนออก และการบีบอัดคือครึ่งที่แพงกว่า สำหรับสมุดงานที่มีแคช pivot ขนาดใหญ่และภาพฝังหลายสิบภาพ ความแตกต่างนี้คือความแตกต่างระหว่างการแพตช์ที่เสร็จในเวลาเท่ากับที่ใช้เขียนชีตใหม่ กับการแพตช์ที่ใช้เวลาส่วนใหญ่ไปกับการบีบอัดไบต์ที่มันไม่เคยตรวจสอบเลยซ้ำ
HotXLS ใช้ CopyCompressedFrom สำหรับสิ่งนี้ ซึ่งเขียนไบต์ที่บีบอัดแล้วของรายการต้นทางลงในอาร์ไคฟ์เป้าหมายโดยตรง เมื่อรายการหนึ่งไม่สามารถคัดลอกด้วยวิธีนั้นได้ เพราะใช้วิธีบีบอัดที่ต่างออกไปหรือการเข้ารหัสที่อ่อนแอ ตัวเขียนจะถอยกลับไปใช้การคัดลอกสตรีมแบบคลายการบีบอัดแทนที่จะล้มเหลว รายการเครื่องหมายไดเรกทอรีจะถูกข้ามไป เพราะตัวเขียนสร้างของตัวเองขึ้นมาอยู่แล้ว
แทนที่ในตำแหน่งเดิม หรือเขียนไปยังไฟล์ใหม่
โอเวอร์โหลดสองรูปแบบครอบคลุมสองรูปแบบที่งานนี้ทำได้ รูปแบบในตำแหน่งเดิมจะเตรียมผลลัพธ์ไว้ในไฟล์ชั่วคราวข้างต้นฉบับ ปิดแฮนเดิลต้นทาง แล้วจึงลบและเปลี่ยนชื่อ ดังนั้นการล่มระหว่างเขียนจะทิ้งต้นฉบับไว้ไม่เสียหาย รูปแบบเป้าหมายชัดเจนจะไม่แตะต้องต้นทาง และสามารถแทนที่ชีตหนึ่งแผ่นหรือต่อท้ายชีตใหม่ได้:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // in place
W.AddSheet('Data');
W.AddRow(1);
W.WriteString(1, 'Region');
W.WriteString(2, 'Revenue');
W.AddRow(2);
W.WriteString(1, 'North');
W.WriteNumber(2, 184320.55);
W.AddRow(3);
W.WriteFormula(1, '=SUM(B2:B2)');
W.Close;
finally
W.Free;
end;
end;
รูปแบบการแทรกรับต้นทางและเส้นทางปลายทาง บวกกับ InsertSheet:
// ต้นทางไม่ถูกแตะต้อง ปลายทางได้เวิร์กชีตเพิ่มชื่อ Extra
W.BeginPatch('template.xlsx', 'output.xlsx', 'Extra', True);
W.AddSheet('Extra');
W.AddRow(1);
W.WriteString(1, 'appended by the nightly job');
W.Close;
การแทรกคือส่วนที่ต้องทำการผ่าตัดบัญชีจริงจัง ตัวเขียนแยกวิเคราะห์ทะเบียนชีตใน xl/workbook.xml และแผนที่ความสัมพันธ์ที่ผูกแต่ละชีตเข้ากับส่วนของมัน แล้วเลือกหมายเลขส่วนว่างถัดไป ตัวระบุชีต และตัวระบุความสัมพันธ์ ประเภทความสัมพันธ์ปฏิบัติตามข้อตกลงของแพ็กเกจต้นทาง ดังนั้นการแพตช์สมุดงาน ISO 29500 แบบ strict จะสร้างประเภทความสัมพันธ์แบบ strict และการแพตช์สมุดงานแบบ transitional จะสร้างประเภทแบบ transitional
สิ่งที่การแพตช์ทิ้งและจำกัดไว้อย่างจงใจ
สายการคำนวณจะถูกทิ้งในทั้งสองโหมด ในโหมดแทนที่ รายการของมันอธิบายเซลล์ในชีตที่ไม่มีอยู่ในรูปแบบนั้นอีกต่อไป ในโหมดแทรก การเลื่อนดัชนีชีตทำให้มันใช้ไม่ได้โดยสิ้นเชิง Excel จะสร้างสายการคำนวณขึ้นใหม่ในการคำนวณครั้งถัดไป ดังนั้นการทิ้งมันจึงถูกต้อง ไม่ใช่การสูญเสียข้อมูล ส่วนนี้ถูกละเว้นจากการคัดลอก และรายการความสัมพันธ์กับการเขียนทับประเภทเนื้อหาของมันถูกลบออกอย่างแม่นยำ
ความหมายในการเขียนสองอย่างเปลี่ยนไปภายในการแพตช์ และทั้งสองอย่างเป็นไปตามหลักการเดียวกัน คือการแพตช์ต้องไม่รบกวนส่วนที่มันไม่ได้เขียนใหม่ สตริงจะถูกเขียนแบบอินไลน์เข้าไปในชีตแทนที่จะเพิ่มลงในตารางสตริงที่ใช้ร่วมกัน เพราะตารางต้นทางข้ามผ่านไปโดยไม่ถูกแตะต้อง และ StyleIndex อ้างอิงไปยังรายการใน cellXfs ของแพ็กเกจต้นทาง ไม่ใช่ตารางสไตล์ที่ตัวเขียนสร้างขึ้น นั่นหมายความว่าคุณสามารถอ้างอิงรูปแบบที่สมุดงานเดิมกำหนดไว้อยู่แล้วได้ ซึ่งมักเป็นสิ่งที่การรีเฟรชข้อมูลต้องการพอดี แต่ก็หมายความว่าคุณต้องรู้ด้วยว่าดัชนีใดพกรูปแบบใด
// ภายในการแพตช์ StyleIndex ทำดัชนีไปยัง cellXfs ของแพ็กเกจต้นทาง
// วันที่ต้องการดัชนีที่ชัดเจนซึ่งแม็ปไปยังรูปแบบวันที่ที่นั่น:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// โอเวอร์โหลด WriteDateTime แบบไม่มีสไตล์ถูกปฏิเสธในโหมดแพตช์
// เพราะมันสมมติว่ามีตารางสไตล์ของตัวเขียนเอง ซึ่งการแพตช์
// ไม่เคยสร้างขึ้นมาเลย
จุดเข้าถึงการเขียนหกจุดถูกกั้นไว้ การเพิ่มตาราง แผนภูมิ ภาพ ความคิดเห็น ชื่อที่กำหนดไว้ และสไตล์เซลล์ ล้วนยกข้อยกเว้นขึ้นในโหมดแพตช์ พร้อมตาข่ายนิรภัยชั้นที่สองในเวลาปิดที่จะล้มเหลวหากตัวนับใดของสิ่งเหล่านี้ไม่เท่ากับศูนย์ แต่ละคุณสมบัติเหล่านี้จะต้องแก้ไขส่วนที่การแพตช์คัดลอกแบบคำต่อคำ และแพ็กเกจที่แก้ไขไปครึ่งหนึ่งย่อมเลวร้ายกว่าการปฏิเสธการทำงาน สามารถแพตช์ได้เพียงหนึ่งชีตต่อหนึ่งการทำงานเท่านั้น
เมื่อใดควรแพตช์ และเมื่อใดควรโหลด
การแพตช์เป็นเครื่องมือที่ถูกต้องเมื่อสมุดงานมีขนาดใหญ่ การเปลี่ยนแปลงจำกัดอยู่ที่ชีตเดียว และส่วนที่เหลือของไฟล์ต้องคงอยู่แบบบิตต่อบิต มันเป็นเครื่องมือที่ผิดเมื่อการเปลี่ยนแปลงครอบคลุมหลายชีต เมื่อต้องการรูปแบบใหม่หรืออ็อบเจกต์ใหม่ หรือเมื่อไฟล์เล็กพอที่การโหลดและบันทึกแบบปกติแทบไม่มีต้นทุนเลย สำหรับการสร้างจำนวนมากตั้งแต่ต้น เส้นทางแบบสตรีมมิงที่อธิบายไว้ในตัวเขียนแบบตรงชนิดสตรีมมิง ยังคงเหมาะสมกว่า และมันใช้ API AddRow กับ Write* ร่วมกัน ดังนั้นการย้ายไปมาระหว่างสองแบบจึงเป็นเรื่องกลไกล้วนๆ
การจัดการระดับชีตภายในสมุดงานที่โหลดไว้ เมื่อคุณต้องการแบบจำลองอ็อบเจกต์แบบเต็มจริงๆ อธิบายไว้ในการทำสำเนาเวิร์กชีตในแพ็กเกจ XLSX และหากเหตุผลที่คุณกำลังพิจารณาการแพตช์คือการประมวลผลสมุดงานทั้งเล่มช้าลง การวัดผลและพฤติกรรมหน่วยความจำในประสิทธิภาพของสมุดงานขนาดใหญ่ ก็ควรอ่านก่อนเลือกแนวทาง
การตรวจสอบว่าการแพตช์ทำสิ่งที่คุณคิดไว้จริงๆ
การตรวจสอบสามอย่างจับข้อผิดพลาดได้เกือบทั้งหมด ยืนยันว่าส่วนที่คุณคาดว่าจะรอดอยู่ยังอยู่ในอาร์ไคฟ์ xl/calcChain.xml หายไป และการเปิดไฟล์ใหม่ผ่าน TXLSXWorkbook รายงานจำนวนชีตตามที่คุณคาดไว้ คือไม่เปลี่ยนแปลงสำหรับการแทนที่ และเพิ่มขึ้นหนึ่งสำหรับการแทรก การอ่านชีตที่แพตช์แล้วกลับมาและเปรียบเทียบค่าและสูตรบางส่วนช่วยปิดวงจรการตรวจสอบ
รายละเอียดการนำไปใช้งานจริงหนึ่งข้อจากการพัฒนาคุณสมบัตินี้ควรกล่าวซ้ำ เพราะมันสามารถกัดกินใครก็ตามที่เขียนโค้ดระดับ zip แบบคล้ายกันได้ ชื่อส่วนเวิร์กชีตถูกจับคู่ด้วยพรีฟิกซ์ และการผิดพลาดหนึ่งหน่วยในความยาวพรีฟิกซ์หมายความว่าเงื่อนไขจะไม่มีวันตรงกันเลย ดังนั้นส่วนที่เขียนขึ้นใหม่จะชนกับชื่อที่มีอยู่แล้ว และตัวอ่านที่รับรายการสุดท้ายที่มีชื่อกำหนดจะเลือกชีตผิดโดยไม่รู้ตัว หากการแพตช์ดูเหมือนสลับเนื้อหาของสองชีต ให้ดูที่การจับคู่ชื่อก่อนดูที่ XML
การแพตช์ในตำแหน่งเดิม การเขียนแบบสตรีมมิง และแบบจำลองอ็อบเจกต์สมุดงานแบบเต็ม มาพร้อมกันในไลบรารีเดียวกันสำหรับ Delphi และ C++Builder รายการคุณสมบัติอยู่ที่หน้าคอมโพเนนต์สเปรดชีต HotXLS สำหรับ Delphi