محتويات الدورة
Dart
الأساسيات: القيم والغياب والمجموعات والكائنات الصالحة
العقود: الأنماط والواجهات العامة والنتائج غير المتزامنة
التكامل: الأهداف والموارد والتحقق والأدلة

Dart / التكامل: الأهداف والموارد والتحقق والأدلة / الدرس 14

امتلاك الموارد واحترام حدود البايت والنص

صمّم الاقتناء والإتمام والتنظيف وفك النص والاستهلاك المحدود، مع تقييد افتراضات dart:io بمنصتها.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • ميّز قبول الكتابة وإتمامها غير المتزامن وإغلاق المورد.
  • فك النص المتدفق عبر قطع البايت دون افتراض أن كل قطعة محرف كامل أو سطر كامل.

سمّ مالك المورد قبل إدخال عمليات I/O

للملفات والمصبات والمقابس والاشتراكات أعمار تتجاوز استدعاء طريقة واحدة. ينبغي أن تقول الواجهة هل تستعير المورد من المستدعي أم تملكه وتغلقه. تستهدف dart:io منصات غير متصفح مدعومة، ولا يجعل استيرادها تجريدا محمولا لملفات المتصفح. تعتمد المسارات والأذونات والترميزات والفشل على البيئة الفعلية. لا ينفذ الدرس ملفات أو مجلدات أو شبكة أو عمليات مضيف. يستخدم نموذجا محليا يسجل العمل وقطعا ثابتة من البايت لشرح الملكية والفك، دون ادعاء فحص مورد نظام تشغيل حقيقي.

اربط التنظيف بالنطاق الذي يملك الكائن

يرفض المصب التسجيلي أدناه الكتابة بعد الإغلاق ويسجل هل أغلقه المالك. تثبت finally مسار تنظيف محليا حتى لو أصبح الجسم يرمي لاحقا. الإغلاق في النموذج متزامن ولا توجد I/O حقيقية؛ فلا يثبت تفريغ IOSink أصلي أو حفظ البيانات على القرص. قد تعيد طريقة تنظيف فعلية Future يجب انتظارها. ميّز الإخفاق الأصلي من إخفاق التنظيف، ولا تستبدل كل خطأ بعلامة إغلاق مطمئنة.

dart نموذج محلي للملكية والإغلاق
class RecordingSink {
  final lines = <String>[];
  bool closed = false;
  void write(String text) {
    if (closed) throw StateError('sink closed');
    lines.add(text);
  }
  void close() { closed = true; }
}
void main() {
  final sink = RecordingSink();
  try {
    sink.write('batch:B-4');
  } finally {
    sink.close();
  }
  print(sink.lines.single);
  print(sink.closed);
}
الناتج المتوقع
batch:B-4
true

المخرج المتوقع batch:B-4 ثم true. تحفظ القائمة نصا واحدا ويسجل العلم إغلاق النموذج فقط. لا يوجد ملف أو مصب أصلي أو اختبار تشغيل.

ليس استدعاء الكتابة شهادة دوام

قد تقبل IOSink بايتات أو ترمز نصوصا مكتوبة، وتحتاج قنوات الإتمام والخطأ غير المتزامن معالجة وفق العقد. لـflush وclose معان محددة، ولا ينبغي تقديمهما ضمان دوام معاملي عام. راقب الخطأ مبكرا بدلا من افتراض أن write المتزامنة تكشف كل فشل لاحق. إذا كتبت العملية تقريرا كاملا فحدّد بقاء المخرج الجزئي وكيف يميز المستدعي الإنجاز من القبول. تحرير المورد ونجاح العمل نتيجتان مرتبطتان منفصلتان، ولا يجعل تنفيذ finally العملية الجزئية آمنة للإعادة تلقائيا.

لا تتبع حدود النص حدود قطع البايت

قد يمتد محرف UTF-8 عبر قطع واردة متعددة، وقد يمتد سطر عبر قطع نص مفكوكة كثيرة. استخدم مفكك UTF-8 المتدفق أولا ثم قسّم النص إلى أسطر. قد يرفض فك كل قطعة مستقلة محرفا صحيحا مقسوما أو يفسده. يقسم المثال عمدا بايتي é ويضع نهاية السطر في القطعة الثانية. يستخدم بيانات الذاكرة وتحويلات المكتبة فقط. ويحتاج الحقيقي سياسة لترميز مشوه وحجم السطر والحجم الكلي ودخول المحتوى الحساس في التشخيص.

dart فك محرف مقسوم بين قطعتين
import 'dart:async';
import 'dart:convert';
Future<void> main() async {
  final bytes = Stream<List<int>>.fromIterable(<List<int>>[
    <int>[0xC3],
    <int>[0xA9, 0x0A],
  ]);
  final lines = bytes.transform(utf8.decoder).transform(const LineSplitter());
  await for (final line in lines) {
    print(line);
  }
}
الناتج المتوقع
é

المخرج المتوقع é في سطر واحد. يحتفظ المفكك بتسلسل UTF-8 الجزئي بين القطعتين. لا تُقرأ بايتات خارجية ولم يُنفذ مصدر Dart.

يحتاج التدفق حدود حجم وفشل أيضا

لا يحد استخدام التدفق الذاكرة بذاته. قد تجسّد toList المصدر كله، ويتراكم سطر هائل قبل تقسيمه، ويخزن تأجيل التسليم بيانات سابقة. ضع حدودا تلائم مدخل المنتج وارفض أو توقف عمدا عند تجاوزها. وللمورد الحقيقي اختبر الإتمام والخطأ الوسطي وخروج المستهلك المبكر وفشل التنظيف في بيئة معزولة مخولة. سجّل افتراضات الهدف والترميز. لا تدعي الدورة فحص سلامة ملف أو إذن أو دوام أو تحرير مورد، وتبقى المخرجات توقعات تحليلية.

الأخطاء الشائعة وإصلاحها

يفشل محرف UTF-8 صحيح عند فك القطع منفصلة.

لماذا يحدث؟
انقسم تسلسل متعدد البايت عبر حد القطع.
كيف تصلحه؟
استخدم المفكك المتدفق قبل تقسيم الأسطر.
كيف تتجنب تكراره؟
أدرج محرفا متعدد البايت مقسوما في فحوص الفك المعزولة.

يعود المالك قبل اكتمال الإغلاق غير المتزامن.

لماذا يحدث؟
اختلط بدء التنظيف بإتمامه.
كيف تصلحه؟
انتظر Future التنظيف المطلوبة للمورد وعالج فشلها.
كيف تتجنب تكراره؟
وثّق الموارد المستعارة والمملوكة وعقود إغلاقها.

يستنفد محلل متدفق الذاكرة عند مدخل هائل.

لماذا يحدث؟
اختلطت صياغة التدفق بمحدودية التخزين وحجم النتيجة.
كيف تصلحه؟
حد الأسطر المتراكمة والمدخل الكلي والنتائج المجسدة.
كيف تتجنب تكراره؟
اختبر التجاوز والتوقف المبكر، لا المدخل الصغير الناجح فقط.

اختبر فهمك

1. لماذا تتجنب واجهة تقبل مصبا يملكه المستدعي إغلاقه بصمت؟

اعرض الحل المشروح

قد يريد المستدعي كتابة مزيد أو إدارة المصب عبر عمليات متعددة. يغير الإغلاق الملكية ويكسر الاستخدام اللاحق. صرّح هل الواجهة تستعير أو تملك المورد، ودع المالك المعلن يغلقه وينتظر. إذا قصد نقل الملكية فاجعله عقدا، ولا تستنتجه من سهولة finally.

2. هل يثبت نجاح flush نجاة تقرير كامل من كل فشل عملية أو جهاز؟

اعرض الحل المشروح

لا. افهم ضمان الواجهة وسلوك التخزين الفعلي بدلا من إسقاط وعد دوام عام عليه. قد يحتاج التقرير الكامل بروتوكول كتابة وفحوص سلامة واستعادة على مستوى التطبيق. يشرح الدرس ملكية محلية وفك تدفق فقط، لا معاملة ملفات أو اختبار انقطاع طاقة.

أهم ما تعلمته

  • ملكية المورد وإتمامه ودوامه وتنظيفه ادعاءات منفصلة.
  • فك النص تدريجيا وحد كل تمثيل متراكم.

المراجع الرسمية