أحيانًا يكون السؤال الوحيد الذي تحتاج روتين استقبال إجابة عنه سؤالًا بنيويًا: هل يملك هذا المصنف ورقة اسمها "Mapping"، أو كم علامة تبويب يحملها. الإجابة عن ذلك باستدعاء Open هي الطريقة المكلفة لفعل ذلك. الفتح الكامل ينفخ جدول السلاسل المشترك، ويفك ترميز كل سجل نمط، ويجتاز خلايا كل ورقة عمل، لأنه لا يملك طريقة لمعرفة أنك أردت فقط جدول المحتويات. على ملف كبير، هذا مئات الميغابايتات من التخصيصات وعدة ثوانٍ من وقت المعالج تُنفق لقراءة قائمة تشغل بضعة كيلوبايتات فقط. HotXLS، مكتبة جداول بيانات Delphi الأصلية من losLab، تمنحك تلك القائمة وحدها: GetSheetNames تعيد أسماء أوراق العمل، بترتيب المصنف، دون تجسيد خلية واحدة
لماذا الفهرس رخيص القراءة
كلا صيغتَي جداول البيانات تضعان جدول محتوياتهما قرب البداية، وهذا ما يجعل استدعاء السرد سريعًا لا ذكيًا فحسب. حزمة OOXML تحفظ فهرس الأوراق في xl/workbook.xml، وهو جزء يبقى صغيرًا سواء كان المصنف يحمل عشرة صفوف أو عشرة ملايين. أما ملف .xls بصيغة BIFF8 فيخزّن سجلات BoundSheet الخاصة به في بداية تدفق عموميات المصنف، قبل أي بيانات خلايا. لذا فإن العمل الذي يتجنبه استدعاء السرد ليس خطأ تقريب مقابل فتح كامل. إنه معظم الملف. قراءة الفهرس تكلف نفس الحفنة من الكيلوبايتات بصرف النظر عن عدد الصفوف، بينما الفتح الكامل يتوسع مع البيانات، وعلى مصنف بعدة ميغابايتات تمتد تلك الفجوة إلى عدة رتب من الحجم في كل من البايتات المُلامَسة والذاكرة المخصَّصة
ذلك الثمن المسطّح هو الخاصية التي تستحق التصميم حولها. بوابة استقبال مبنية على GetSheetNames تتصرف بنفس الطريقة على ملف من 200 صف وملف من 200 ميغابايت، فلم يعد أبطأ ملف في دفعة يحدد وتيرة القرار بشأن ما إذا كان الملف يستحق المعالجة أصلًا
استدعاء واحد عبر .xls و.xlsx وصيغ القالب
في واجهة XLS، TXLSWorkbook.GetSheetNames تقرأ أكثر من .xls وحده. إنها تقبل أيضًا الصيغ المبنية على الأرشيف المضغوط .xlsx و.xlsm و.xltx و.xltm، ساحبة workbook.xml فقط من الأرشيف. لإدخال .xls حقيقي، تفحص سجلات BoundSheet وتتوقف عند أول سجل EOF في التدفق الفرعي للعموميات، فيظل الملف الثنائي الكبير يكلف فقط كيلوبايتاته الافتتاحية. واجهة XLSX تحمل ضمانًا أهم مما يبدو للوهلة الأولى لكود خدمة طويل التشغيل: TXLSXWorkbook.GetSheetNames لا تعيد ضبط كائن المصنف ولا تملؤه، فيمكن لكائن يحمل بالفعل مستندًا مفتوحًا أن يفحص ملفات أخرى دون إزعاج الملف الذي بيده. GetODSSheetNames تطبّق النهج نفسه على حزم OpenDocument، ولكل واحد من هذه الاستدعاءات حمولة زائدة من نوع تدفق، وهذا يتيح لك فحص ملف مرفوع لم يهبط على القرص أبدًا
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;
الاستدعاء نفسه يصنع مربع حوار استيراد جيدًا على سطح المكتب. اسرد الأوراق، ودع المستخدم يختار واحدة، وادفع ثمن الفتح الكامل فقط بعد أن يُتَّخذ الاختيار. مع مصنف من خمسين ورقة، الفرق مرئي: منتقٍ يظهر فورًا مقابل منتقٍ يتعثر بينما يُحمَّل الملف بأكمله خلفه
ملفات .xlsm المُفعَّلة للماكرو وصيغ القالب تُسرَد تمامًا كملف .xlsx عادي، لأن الفهرس يقع في نفس workbook.xml سواء كان vbaProject.bin راكبًا معه في الحزمة أم لا. خط أنابيب استقبال يمكنه إذن تعداد أوراق مصنف يحمل ماكرو للتوجيه، دون لمس حمولة الماكرو مطلقًا ودون فعل أي شيء قد يشغّلها، تاركًا قرار سياسة الماكرو للمرحلة التي تفتح الملف فعليًا
قراءة القيمة المُعادة دون خداع نفسك
اصطلاحات القيمة المُعادة ليست موحّدة عبر HotXLS. بعض الاستدعاءات تعيد 1 عند النجاح، وأخرى تعيد عددًا، لذا فإن الفحص الوحيد الصامد لدوال السرد هو معاملة أي قيمة صفر أو أقل على أنها فشل، مع تفريغ قائمة السلاسل. قاوم إغراء قراءة قائمة فارغة على أنها "مصنف بلا أوراق". كل من ECMA-376 ومواصفة BIFF8 يشترطان ورقة واحدة على الأقل في مصنف صالح، فصفر أسماء يعني دائمًا فشل القراءة، لا أن الملف فارغ شرعيًا أبدًا
سرد فاشل هو نفسه إشارة تستحق الاحتفاظ بها. ملف .xlsx يفشل في الاستدعاء هو واحد من بضعة أشياء محددة: مقطوع، أو ليس حزمة OOXML حقيقية على الإطلاق (ملفات CSV مُصدَّرة من أنظمة أخرى وموسومة خطأً تظهر هنا باستمرار)، أو حاوية مشفّرة. التفريق بين هذه هو مهمة الفحص التالي. تسجيل البايتات الأولى للملف المرفوض إلى جانب الفشل عادة ما يحوّل خيط دعم إلى رسالة واحدة
اكتشاف الحاويات المشفّرة قبل التوجيه
ملف .xlsx مشفّر ليس أرشيفًا مضغوطًا. إنه ملف OLE مركّب يغلّف تدفقات EncryptionInfo وEncryptedPackage، فـGetSheetNames لا تستطيع الرؤية داخله وتعيد فشلًا مثل أي ملف آخر غير قابل للقراءة. CanReadEncrypted تختبر شكل تلك الحاوية، وهذا يتيح للاستقبال توجيه ملف مشفّر عن قصد بدلًا من ابتلاع خطأ قراءة عام من مكان عميق داخل عملية عامل:
type
TIntakeRoute = (irNormal, irNeedsPassword, irUnreadable);
function ClassifyUpload(const FileName: string; Names: TStrings): TIntakeRoute;
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// OOXML المشفّر حاوية OLE، لا أرشيف مضغوط: تحقق أولًا،
// لأن استدعاءات السرد لا تستطيع النظر داخله.
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;
التشفير هو حيث يكون HotXLS غير متماثل عمدًا، لذا يجب أن يحترم التوجيه ذلك. تشفير .xls القديم (RC4، وRC4 CryptoAPI، وXOR) قابل للقراءة: TXLSWorkbook.Open(FileName, Password) يفك التشفير بكلمة مرور مخزَّنة، ويمكن لتلك الملفات البقاء على المسار الآلي. أما حزم OOXML المشفّرة فتسير في الاتجاه الآخر. يستطيع HotXLS كتابة واحدة عبر SaveAsEncrypted، لكنه لا يستطيع قراءتها مجددًا. OpenEncrypted تثير EXlsxEncryptionNotImplemented عند تسليمها حزمة مشفّرة، وهذا سبب أن تصميم استقبال صادق يرسل .xlsx المشفّر إلى شخص لديه Excel ويبقي .xls الحامل لكلمة المرور داخل الكود
لعمل الدُفعات، هذا المصنِّف يكسب مكانته بتشغيله عبر مجلد وارد بأكمله قبل أن يبدأ أي عامل معالجة حقيقية، لأن كل فحص يكلف تقريبًا فتح ملف واحد وبضعة كيلوبايتات من القراءات. تحميله مقدَّمًا يغيّر نمط الفشل الذي يهم العمليات فعلًا. بدلًا من مهمة الساعة الثالثة صباحًا تموت عند الملف 412 من 600، تحصل على 412 ملفًا في قائمة الانتظار و5 مرفوضة عند الاستقبال مع سبب مرفق بكل واحد. نفس استدعاءات المكتبة، قصة تشغيلية أفضل بكثير
الأسئلة التي لا يستطيع استدعاء السرد الإجابة عنها
الأسماء والترتيب هما كل ما تحصل عليه. استدعاءات السرد لا تقول شيئًا عن الرؤية، فالأوراق المخفية والمخفية جدًا تصل في القائمة وكأنها أي ورقة أخرى. لا تُبلغ عن أبعاد النطاق المستخدم، ولا عدد الخلايا، ولا خصائص المستند. جزء docProps/core.xml صغير أيضًا، لكن لا يوجد فحص خاص بالخصائص فقط اليوم، فبيانات المؤلف والعنوان الوصفية لا تزال تكلف Open كاملًا. الطريقة النظيفة للتعايش مع ذلك هي ترك الحقائق الرخيصة توجّه كل ملف وحجز الحقائق المكلفة للملفات التي تنجو من التوجيه. للملفات التي تمضي فعلًا إلى قراءة عميقة، فحص للقراءة فقط لملف .xls كبير يعمل أسرع بشكل ملحوظ مع _DisableGraphics := True، التي تتخطى تحليل OfficeArt. فقط لا تحفظ أبدًا من ذلك الكائن: طبقة الرسم التي تخطّاها اختفت من النموذج، والحفظ سيُسقطها من الملف
الملفات التي تجتاز الفرز عادة ما تتجه إلى تحليل أعمق. منصة تدقيق المصنفات وتحويلها تغطي العدادات لكل ورقة التي تستحق الجمع بمجرد أن يصبح الفتح الكامل مبررًا، ودليل أداء المصنفات الكبيرة يغطي إبقاء ذلك الفتح الكامل سريعًا
HotXLS مكتبة جداول بيانات Object Pascal أصلية لـDelphi وC++Builder؛ سطح API الكامل، بما في ذلك استدعاءات الفحص المعروضة هنا، موثَّق على صفحة منتج HotXLS Delphi Component