يستطيع HotXLS إعادة كتابة ورقة عمل واحدة داخل حزمة XLSX موجودة من دون تحليل بقية الملف أو إعادة ضغطه. يفتح TXLSDirectWriter.BeginPatch حزمة مصدر، وينسخ كل مُدخَل باستثناء الورقة المستهدفة ببايتاته المضغوطة كما هي، ويتيح لك إعادة تأليف تلك الورقة الواحدة عبر استدعاءات AddSheet وAddRow وWrite* الاعتيادية. ولا تُفكَّك المخططات البيانية، وذاكرات PivotTable المؤقتة، والسمات، والأنماط، والسلاسل النصية المشتركة أبدًا
وسير العمل الذي يحلّه هذا يظهر في التقارير وتحديث البيانات. فمصنّف يصل من فريق أعمال يحمل جداول PivotTable، وأدوات تقطيع، وتنسيقات شرطية، وعقدًا من التنسيق المتراكم. وفي كل ليلة يجب استبدال ورقة بيانات واحدة بأرقام جديدة. وتحميل المصنّف بأكمله وإعادة حفظه يكلّف دقائق لكل ملف، والأهم من ذلك، يخاطر بدقّة الميزات التي يتعيّن على محرك التحميل إعادة بنائها. ويتجنب الترقيع كلتا المشكلتين بعدم لمس ما لا يحتاج إلى لمسه
لماذا يمثّل نسخ البايتات المضغوطة الجزء المثير للاهتمام؟
مُدخَل zip يُنسَخ على المستوى المضغوط يكلّف نسخ تدفق فحسب. أما المُدخَل نفسه إذا مرّ عبر مسار كتابة عادي فيكلّف فك ضغط عند الدخول وضغطًا عند الخروج، والضغط هو النصف المكلف. وفي مصنّف يحتوي على ذاكرة PivotTable مؤقتة كبيرة وبضع عشرات من الصور المضمَّنة، يكون هذا الفرق هو الفرق بين ترقيع ينتهي في الوقت الذي يستغرقه كتابة الورقة الجديدة، وترقيع يقضي معظم وقته في إعادة ضغط بايتات لم يفحصها قط
يستخدم HotXLS CopyCompressedFrom لهذا الغرض، الذي يكتب البايتات المضغوطة لمُدخَل المصدر مباشرة في الأرشيف الهدف. وحين يتعذّر نسخ مُدخَل بهذه الطريقة، بسبب استخدامه طريقة ضغط مختلفة أو تشفيرًا ضعيفًا، يعود الكاتب إلى نسخ تدفق مفكوك الضغط بدلًا من الفشل. وتُتخطى مُدخَلات علامات الدليل، لأن الكاتب يُنتج مُدخَلاته الخاصة
الاستبدال في الموضع، أو الكتابة إلى ملف جديد
يُغطّي حمولتان زائدتان الشكلين اللذين تتخذهما هذه المهمة. يُجهِّز الشكل في الموضع النتيجة في ملف مؤقت إلى جانب الأصل، ويُغلق مقبض المصدر، ثم يحذف ويعيد التسمية، بحيث يترك أي انهيار في منتصف الكتابة الأصل سليمًا. أما شكل الهدف الصريح فيترك المصدر دون لمس، ويستطيع إما استبدال ورقة أو إلحاق ورقة جديدة:
var
W: TXLSDirectWriter;
begin
W := TXLSDirectWriter.Create;
try
W.BeginPatch('monthly-dashboard.xlsx', 'Data'); // في الموضع
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 الصارمة أنواع علاقات صارمة، ويُصدر ترقيع مصنّف انتقالي أنواع علاقات انتقالية
ما يُسقطه الترقيع ويقيّده عمدًا
تُسقَط سلسلة الحساب في كلا الوضعين. ففي وضع الاستبدال، تصف مُدخَلاتها خلايا في ورقة لم تعد موجودة بتلك الصيغة؛ وفي وضع الإدراج، يُبطلها انزياح فهرس الورقة تمامًا. ويعيد Excel بناء السلسلة عند إعادة الحساب التالية، لذا فإن إسقاطها صحيح لا فقدان فيه. ويُستبعَد الجزء من النسخ، ويُزال مُدخَل علاقته وتجاوز نوع المحتوى الخاص به جراحيًا
وتتغيّر دلالتان في التأليف داخل الترقيع، وكلتاهما تتبعان المبدأ نفسه: يجب ألا يُقلق الترقيع أجزاء لم يُعد كتابتها. فالسلاسل النصية تُكتب مضمّنة داخل الورقة بدلًا من إضافتها إلى جدول السلاسل النصية المشتركة، لأن جدول المصدر ينتقل دون لمس. أما StyleIndex فيشير إلى مُدخَلات في cellXfs الخاص بحزمة المصدر، لا إلى جدول أنماط يبنيه الكاتب. وهذا يعني أنه يمكنك الإشارة إلى تنسيقات يُعرّفها المصنّف الأصلي بالفعل، وهو عادة بالضبط ما يريده تحديث البيانات، لكنه يعني أيضًا أنه يجب عليك معرفة أي فهرس يحمل أي تنسيق
// داخل الترقيع، يُفهرِس StyleIndex الـ cellXfs الخاص بحزمة المصدر
// يحتاج التاريخ إلى فهرس صريح يُطابِق تنسيق تاريخ هناك:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// تُرفَض الحمولة الزائدة الخالية من النمط لـ WriteDateTime في وضع الترقيع،
// لأنها تفترض جدول أنماط الكاتب الخاص، وهو ما لا ينشئه الترقيع أبدًا
وتخضع ستة نقاط دخول للتأليف لبوابة تحكم: إضافة جداول، ومخططات بيانية، وصور، وتعليقات، وأسماء معرَّفة، وأنماط خلايا، كلها ترفع استثناءً في وضع الترقيع، مع شبكة أمان ثانية عند الإغلاق تفشل إذا كان أي من عداداتها غير صفري. وكل واحدة من هذه الميزات ستتطلب تحرير أجزاء ينسخها الترقيع حرفيًا، والحزمة نصف المُحرَّرة أسوأ من عملية مرفوضة. ويمكن ترقيع ورقة واحدة بالضبط لكل عملية
متى تُرقّع ومتى تُحمِّل
الترقيع هو الأداة الصحيحة حين يكون المصنّف كبيرًا، والتغيير محصورًا في ورقة واحدة، ويجب أن تبقى بقية الملف سليمة بت ببت. وهو الأداة الخاطئة حين يمتد التغيير عبر عدة أوراق، أو حين تكون هناك حاجة إلى تنسيق جديد أو كائنات جديدة، أو حين يكون الملف صغيرًا بما يكفي بحيث لا يكلّف التحميل والحفظ العاديان شيئًا. أما بالنسبة إلى التوليد الجماعي من الصفر، فيبقى المسار المتدفق الموصوف في الكاتب المباشر المتدفق الخيار الأنسب، وهو يشترك في واجهة AddRow وWrite* نفسها، بحيث يكون الانتقال بينهما آليًا
ويُغطّى التعامل على مستوى الورقة داخل مصنّف محمَّل، حين تريد فعلًا نموذج الكائن الكامل، في استنساخ أوراق العمل في حزم XLSX. وإذا كان سبب تفكيرك في الترقيع هو أن معالجة المصنّف بأكمله أصبحت بطيئة، فيستحق القياسات وسلوك الذاكرة في أداء المصنّفات الكبيرة القراءة قبل اختيار نهج
التحقق من أن الترقيع فعل ما تعتقده فعليًا
ثلاثة فحوصات تلتقط تقريبًا كل خطأ. تأكد من أن الأجزاء التي توقعت بقاءها لا تزال في الأرشيف، وأن xl/calcChain.xml قد اختفى، وأن إعادة فتح الملف عبر TXLSXWorkbook تُبلغ عن عدد الأوراق الذي تتوقعه، دون تغيير في حالة الاستبدال ومُزادًا بواحد في حالة الإدراج. وإعادة قراءة الورقة المُرقَّعة ومقارنة بضع قيم وصيغ تُغلق الحلقة
وتفصيل تنفيذ واحد من تطوير هذه الميزة يستحق التكرار، لأنه يمكن أن يُوقِع من يكتب كودًا مماثلًا على مستوى zip. فأسماء أجزاء ورقة العمل تُطابَق بالبادئة، وخطأ بمقدار واحد في طول البادئة يعني أن المُسنِد لا يتطابق أبدًا، بحيث يتصادم جزء مكتوب حديثًا مع اسم موجود، والقارئات التي تأخذ آخر مُدخَل بالاسم نفسه تختار بصمت الورقة الخاطئة. وإذا بدا أن ترقيعًا قد بدّل محتوى ورقتين، فانظر إلى مطابقة الأسماء قبل النظر إلى XML
ويُشحَن الترقيع في الموضع، والكتابة المتدفقة، ونموذج كائن المصنّف الكامل ضمن المكتبة نفسها لـ Delphi وC++Builder؛ وتوجد قائمة الميزات على صفحة مكوّن HotXLS لجداول البيانات في Delphi