كيفية قراءة مئات الآلاف من الصفوف في برنامج Excel دون ملء الذاكرة مرة واحدة
توفر هذه المقالة حلاً برمجيًا دفاعيًا يتضمن إصلاح الأبعاد وإصدار أمان الموارد والتحقق من التكامل لمعالجة مشكلات تجاوز سعة الذاكرة واقتطاع البيانات الخاصة بقراءة الملفات الكبيرة في وضع openpyxl للقراءة فقط. تم توضيح شروط الحدود ومعايير المراجعة اليدوية، وتم توفير نقاط الاتصال المحددة للمقارنة والقبول ثنائي اللغة مع OmniDoc.
كيف تقرأ جدولاً كبيراً دون استهلاك الذاكرة؟ هذه المقالة مخصصة للمطورين وفرق البيانات الذين يحتاجون إلى استخدام Python لمعالجة مئات الآلاف من صفوف Excel. بعد القراءة، ستعرف أسباب انفجار ذاكرة الملفات الكبيرة واقتطاع البيانات، وكيفية استخدام وضع القراءة فقط في openpyxl وإصلاح الأبعاد وتحرير الموارد لمنع هذه المشكلات.
تستخدم الأمثلة الواردة في هذه المقالة العينات الاصطناعية. تم فحص الكود باستخدام أمثلة في بيئة معزولة، لكن هذا لا يضمن جميع الملفات الحقيقية أو أداء المنتج. قبل معالجة المستندات المهمة، يرجى الاحتفاظ بالنسخ الأصلية ومراجعتها وفقًا للحدود وبنود القبول في النص.
كيف تقرأ جدولاً كبيراً دون استنزاف الذاكرة؟ استنتاج جملة واحدة
استخدم read_only=True لدفق قراءة الملفات الكبيرة وإغلاق المصنف بشكل صريح بعد القراءة؛ إذا كان عدد الأسطر المقروءة صغيرًا جدًا، فتحقق أولاً من معلومات أبعاد الملف، ثم قم بدمجها مع المقارنة اليدوية للتأكد من اكتمال البيانات.
| حالتك | الممارسات الموصى بها | سبب |
|---|---|---|
| يؤدي فتح الملفات الكبيرة في الوضع الافتراضي إلى استنفاد الذاكرة بسرعة | استخدم القراءة المتدفقة read_only=True بدلاً من ذلك | سيقوم الوضع الافتراضي بتحميل كافة كائنات الخلية وأنماطها وتعليقاتها وبيانات التعريف الأخرى في الذاكرة مرة واحدة |
| يقرأ فقط بضعة آلاف من الأسطر الأولى وينتهي دون الإبلاغ عن خطأ. | استخدم reset_dimensions() للإصلاح وإعادة القراءة، وضبط الحد الأدنى لعدد الأسطر والنتيجة النهائية | يثق وضع القراءة فقط في dimensions المعلن في الملف. إذا تمت كتابته بشكل غير صحيح، فسيتم إنهاء المكرر مبكرًا. |
| البرنامج النصي ETL الذي يتكرر عبر ملفات متعددة | استدعاء wb.close() بشكل صريح في كتلة finally | سيؤدي عدم الإغلاق إلى تسرب مقبض الملف، مما يؤدي في النهاية إلى تشغيل OSError: Too many open files |
| البيانات التي سيتم استخدامها في العمليات الرسمية | تصدير السجلات مقابل النظام المصدر وإجراء مراجعة يدوية للعينات | تشغيل الكود لا يعني أن البيانات صحيحة |
السبب المباشر لانفجار الذاكرة أو انقطاع البيانات عند قراءة مئات الآلاف من الصفوف في برنامج Excel
عند استخدام load_workbook('huge.xlsx') لفتح جدول يحتوي على نصف مليون صف، قد يستخدم البرنامج ما يصل إلى 8 غيغابايت من الذاكرة في بضع ثوانٍ، أو قد ينتهي بعد قراءة أول 1000 صف فقط.
السبب الأول هو أن الوضع الافتراضي يقوم بتحميل كافة كائنات الخلية وأنماطها وتعليقاتها وبيانات التعريف الأخرى في الذاكرة مرة واحدة. السبب الأخير هو أنه في وضع read_only=True، يثق openpyxl تمامًا في سمة dimensions المعلنة داخل الملف من أجل متابعة الأداء.
إذا كان النظام الذي أنشأ الملف (مثل بعض وحدات تصدير ERP القديمة أو مكتبة Python غير القياسية) يكتب هذه البيانات التعريفية بشكل غير صحيح، فسيتم إنهاء المكرر قبل الأوان دون طرح أي استثناء. هذا ليس خطأ برمجيًا، ولكنه فجوة بين مواصفات التنسيق وبيانات العالم الحقيقي التي يجب سدها من خلال البرمجة الدفاعية.
طريقة الفتح الصحيحة وتحرير الموارد لوضع القراءة فقط
read_only=True هو المسار الرئيسي للتعامل مع الملفات الكبيرة، ولكنه يغير إدارة دورة حياة الكائنات. ستقوم المصنفات العادية بتحرير الموارد تلقائيًا أثناء تجميع البيانات المهملة، بينما تحتفظ المصنفات المخصصة للقراءة فقط بمراجع إلى تدفق ملفات ZIP ومحلل XML في الأسفل ويجب أن تستدعي wb.close() بشكل صريح. للحصول على الإرشادات الرسمية حول وضع القراءة فقط، يرجى الرجوع إلى الوثائق الرسمية للأوضاع المحسنة لـ openpyxl.
يمكن أن يؤدي نسيان هذه الخطوة في البرنامج النصي ETL الذي يتكرر عبر ملفات متعددة إلى تسرب مقبض الملف، مما يؤدي في النهاية إلى تشغيل OSError: Too many open files. غالبًا ما يتم الكشف عن هذا النوع من الأخطاء بعد التشغيل لعدة ساعات ويكون من الصعب للغاية استكشاف الأخطاء وإصلاحها.
بالإضافة إلى ذلك، يقوم وضع القراءة فقط بإرجاع ReadOnlyCell بدلاً من كائن Cell القياسي. ولا يدعم الوصول إلى سمات مثل الأنماط والتعليقات التوضيحية، كما أنه لا يسمح بالبحث العكسي أو تعديل القيم من خلال الإحداثيات. إذا حصلت على معلومات المنطقة المدمجة أو قمت بتعيين لون الخلية أثناء التكرار، فستحصل على AttributeError. تم تصميم هذا الحد للحفاظ على بصمة ذاكرة شبه ثابتة.
📊 المقارنة الأساسية
| البند المقارن | الوضع الافتراضي | وضع القراءة فقط |
|---|---|---|
| استخدام الذاكرة | قم بتحميل جميع كائنات الخلية وبيانات التعريف مرة واحدة، حيث يمكن أن تنفد الذاكرة من الملفات الكبيرة بسهولة | تدفق القراءة، واستخدام الذاكرة قريب من ثابت |
| كائن الخلية الذي تم إرجاعه | معيار Cell | ReadOnlyCell |
| النمط، الوصول إلى التعليقات التوضيحية | يدعم | غير مدعوم، سيؤدي الوصول إلى AttributeError |
| تعديل القيمة أو تعيين اللون | يدعم | غير معتمد |
dimensions الذي يعتمد على الملف | لا تعتمد على | التبعيات، إذا تمت كتابتها بشكل غير صحيح، فقد ينتهي التكرار مبكرًا |
| الافراج عن الموارد | يتم إصداره تلقائيًا أثناء جمع القمامة | يتطلب استدعاء صريح لـ wb.close() |
مثال تركيبي: إصلاح البعد والتحقق من أمان التكرار
يُظهر الكود التالي عملية قراءة دفاعية نموذجية. لاحظ أن هذا مثال اصطناعي يستخدم لتوضيح البنية المنطقية، وليس نتيجة معالجة بيانات الإنتاج الحقيقية. تحتاج إلى إعداد ملف باسم input_large.xlsx لتشغيل هذا البرنامج النصي، ويجب تنفيذه في بيئة معزولة تؤمن الإصدارات التابعة. لا تتضمن العينة عمليات الشبكة أو أوامر shell أو بيانات الاعتماد الحساسة.
from openpyxl import load_workbook
# 合成示例:演示read_only模式下的安全读取与维度校验
# 依赖:openpyxl (需在项目requirements中锁定具体版本)
# 注意:需读者自备 input_large.xlsx,本示例不包含真实数据
def safe_read_large_excel(filepath, expected_min_rows=1000):
"""
安全读取大Excel文件,包含维度修复与完整性校验。
:param filepath: Excel文件路径
:param expected_min_rows: 业务预期的最小行数阈值
:return: 实际读取的行数
"""
wb = load_workbook(filename=filepath, read_only=True)
try:
ws = wb.active
# 检查并修复可能错误的维度声明
# calculate_dimension() 可能返回 'A1:A1' 或其他不准确范围
dim = ws.calculate_dimension()
if dim == "A1:A1" or not dim:
# 重置维度以强制扫描实际数据区域
# 警告:若文件完全无维度信息,此操作可能遍历全表(104万行)
ws.reset_dimensions()
row_count = 0
header = None
for row in ws.iter_rows(values_only=True):
if row_count == 0:
header = row
assert header is not None and any(v is not None for v in header), \
"首行不应为空或全None"
row_count += 1
# 模拟业务处理,避免全量加载到内存
if row_count % 10000 == 0:
print(f"已处理 {row_count} 行")
# 校验读取完整性
assert row_count >= expected_min_rows, \
f"行数不足: 期望>={expected_min_rows}, 实际={row_count}。请检查源文件或维度设置。"
return row_count
finally:
# 必须显式关闭,防止句柄泄漏
wb.close()
# 使用示例(需替换为真实文件路径)
# total = safe_read_large_excel("input_large.xlsx", expected_min_rows=50000)
مفتاح هذا الكود ليس القراءة نفسها، بل طبقات الحماية الثلاث:
- إعادة ضبط البعد: تم إصلاح
dimensionsفي تعريف الملف لتجنب النهاية المبكرة للمكرر. - عد البث: حساب عدد الأسطر أثناء القراءة لتسهيل المقارنة مع التوقعات.
- الإغلاق القسري في
finally: بغض النظر عما إذا كانت القراءة ناجحة أو حدث خطأ في المنتصف، يتم تحرير موارد الملف.
expected_min_rows لا يعد حدًا قياسيًا للصناعة، ولكنه يمثل الحد الأدنى للأعمال استنادًا إلى معرفتك السابقة بالبيانات المصدر. إذا كان العدد الفعلي للصفوف أقل من هذه القيمة، فقد يكون الملف تالفًا أو فشل إصلاح البعد، ويجب إحباطه في هذا الوقت بدلاً من قبول البيانات غير الكاملة بصمت.
معايير القبول وحدود المراجعة اليدوية
لا يعني مجرد إمكانية تشغيل الكود أن البيانات صحيحة. يسرد الجدول التالي الاستثناءات النموذجية التي قد تتم مواجهتها في المشاريع الفعلية وكيفية التعامل معها، مع التمييز بين النطاق الذي يمكن أن تغطيه الأتمتة والسيناريوهات التي تتطلب التدخل اليدوي.
| مراقبة الظواهر | الأسباب المحتملة | المعالجة الآلية | متطلبات المراجعة اليدوية |
|---|---|---|---|
| عدد الصفوف المقروءة أقل بكثير من المتوقع | خطأ في سمة الأبعاد | حاول إعادة القراءة بعدset_dimensions | قارن سجل تصدير النظام المصدر للتأكد مما إذا كان مفقودًا بالفعل. |
| يزداد استهلاك الوقت بشكل كبير بعد إعادة تعيين الأبعاد | لا يحتوي الملف على معلومات الأبعاد، مما يؤدي إلى إجراء فحص كامل للجدول | قم بتعيين الحد الأقصى للصف أو سياسة إنهاء الصف الفارغ | قم بتقييم جودة منشئ الملفات وإجراء الإصلاحات الأولية |
| بعض قيم الخلايا لا شيء | الخلايا المدمجة أو الصيغة لا يتم حسابها | سجل الموقع، تخطي | تحقق مما إذا كانت المنطقة الموجودة في الملف الأصلي مدمجة بشكل مرئي |
| iter_rows في منتصف الطريق StopIteration | دفق XML تالف أو ZIP مجزأ | قبض على الاستثناء وسجل الإزاحة | افتح يدويًا باستخدام Excel أو WPS وتحقق من المنطقة المقابلة |
| الذاكرة تنمو ببطء | لم يتم إغلاقه أو لم يتم تحرير ذاكرة التخزين المؤقت | فرض مراقبة ما بعد gc.collect() | تحقق مما إذا كان هناك متغير عام يحمل مرجع الخلية |
| يحتوي اسم حقل الرأس على أحرف غير مرئية | مشكلة في ترميز نظام التصدير | قطاع () نظيف | تأكيد علاقة رسم الخرائط الميدانية مع طرف العمل |
ملاحظة خاصة: reset_dimensions() ليس حلا سحريا. إذا لم تتم كتابة معلومات البعد إلى الملف نفسه، فقد تقوم هذه الطريقة بتوسيع النطاق إلى الحد الأعلى لورقة العمل (1048576 صفًا)، مما يؤدي إلى اجتياز غير صالح أو حتى انتهاء المهلة. في هذا الوقت، يجب استخدام max_row لتعيين حد أعلى معقول يدويًا، أو يجب إنهاؤه بشكل نشط عند مواجهة N أسطر فارغة على التوالي. لا يمكن إصدار هذه الأحكام عن طريق الكود وحده وتتطلب دعمًا من المعرفة بالمجال.
🎯 ما هي الطريقة المناسبة لك؟
إذا كنت بحاجة إلى معالجة الجداول التي تحتوي على مئات الآلاف من الصفوف في وقت واحد
استخدم القراءة المتدفقة read_only=True لتجنب انفجار الذاكرة في الوضع الافتراضي.
إذا كان البرنامج النصي الخاص بك يتكرر عبر ملفات متعددة
قم باستدعاء wb.close() بشكل صريح في كتلة finally لمنع تسرب المقبض.
إذا كان عدد الصفوف المقروءة أقل بكثير من البيانات المصدر
تحقق أولاً مما إذا كان dimensions مكتوبًا بشكل غير صحيح، وحاول reset_dimensions() ثم أعد قراءته، وقارنه بسجل التصدير الخاص بالنظام المصدر.
إذا كنت بحاجة إلى قراءة الأنماط أو التعليقات
هذه الخصائص غير مدعومة في وضع القراءة فقط ويجب استخدامها في الوضع الافتراضي بدلاً من ذلك، أو التعامل معها بشكل منفصل في عملية أخرى.
إدخال تنفيذ عينة الذاكرة
يتم تشغيل التعليمة البرمجية التالية بعد الوظيفة المذكورة أعلاه وتستخدم البيانات الاصطناعية فقط ولا تقرأ ملف العميل.
from io import BytesIO
from openpyxl import Workbook
source = Workbook()
source.active.append(["id", "value"])
source.active.append(["A", 1])
source.active.append(["B", 2])
out = BytesIO()
source.save(out)
out.seek(0)
assert safe_read_large_excel(out, expected_min_rows=3) == 3
استخدم قائمة المراجعة هذه لترجمة المستندات
حدد أولاً المحتوى الذي يمثل نصًا والمحتوى الذي يمثل الصيغة وترميز الأعمال، ثم قم بترجمة الجدول. لا يتحقق فحص ما بعد الترجمة من إمكانية تحويل اللغة الصينية إلى اللغة الهدف فحسب، بل يؤكد أيضًا ما إذا كانت الصيغ والمعرفات والعلاقات المرجعية قد تم تغييرها.
يوفر موقع OmniDoc (بوابة المنتج) بوابة لترجمة المستندات متعددة التنسيقات، ويقدم الموقع الرسمي وظائف التعرف الضوئي على الحروف (OCR) والمسرد ووظائف المقارنة ثنائية اللغة. بالنسبة للفرق التي ترغب في العمل مباشرة من الملفات، فهذا مسار يستحق التقييم باستخدام عينات من الحياة الواقعية. الرجاء استخدام الملفات غير الحساسة التي لديك إذن بتحميلها، واستخدام عناصر الاختيار في هذه المقالة لمراجعة النتائج. لا تدعي هذه المقالة أن OmniDoc يستخدم مكتبات مفتوحة المصدر أو خوارزميات داخلية في المقالة، ولا تستخدم أمثلة لتحل محل اختبار أداء المنتج.
❓ الأسئلة الشائعة (الأسئلة الشائعة)
1. لماذا تنتهي في منتصف القراءة ولا يتم الإبلاغ عن أي خطأ؟
لأن وضع القراءة فقط يثق في dimensions المعلن بواسطة الملف. إذا كتب نظام البناء هذه البيانات التعريفية بشكل غير صحيح، فسيتم إنهاء المكرر قبل الأوان دون طرح استثناء.
2. هل يمكن حل جميع الملفات الكبيرة باستخدام Reset_dimensions()؟
لا أستطيع. إذا كان الملف نفسه لا يحتوي على معلومات البعد، فقد تقوم هذه الطريقة بتوسيع النطاق إلى 1048576 صفًا، مما يتسبب في انتهاء المهلة ويجب دمجه مع سياسة max_row أو سياسة إنهاء السطر الفارغ المستمر.
3. لماذا لا أستطيع قراءة الأنماط أو تعديل الخلايا في وضع القراءة فقط؟
يقوم وضع القراءة فقط بإرجاع ReadOnlyCell، ولا يدعم الوصول إلى النمط والتعليقات التوضيحية، ولا يسمح بتعديل القيم. هذا للحفاظ على بصمة ذاكرة ثابتة تقريبًا.
4. ما الذي يجب أن أتحقق منه بعد ترجمة النموذج؟
بالإضافة إلى اللغة الصحيحة، تحقق من تغيير الصيغ والمعرفات والعلاقات المرجعية.
📝 ملخص
يكمن مفتاح قراءة الجداول الكبيرة في تدفق القراءة والتحقق من الأبعاد وإطلاق الموارد في الوقت المناسب. الكود هو مجرد نقطة البداية، ويعتمد اكتمال البيانات على المقارنة والمراجعة اليدوية.
جربه الآن: قم بتحميل المستند لبدء الترجمة، مع الاحتفاظ بالتخطيط الأصلي


