استخدام تعيين الذاكرة للملفات الكبيرة في دلفي
نادرًا ما أستخدم تعيين الذاكرة للملفات الكبيرة، وقد واجهت مثل هذا المطلب، لذلك قمت بتسجيل العملية لإعطائك مقدمة، نظرًا لأن التطبيق ليس معقدًا، فقد تكون هناك أشياء لا يمكن أخذها في الاعتبار.
بالنسبة لبعض الملفات الصغيرة، يمكن استخدام تدفقات الملفات العادية لحل المشكلة، ومع ذلك، بالنسبة للملفات الكبيرة جدًا، مثل 2G أو أكثر، لن تعمل تدفقات الملفات، لذلك تحتاج إلى استخدام الأساليب المتعلقة بتعيين الذاكرة في واجهة برمجة التطبيقات (API). إذا كان تعيينًا للذاكرة، فلا يمكن تعيين حجم الملف بالكامل مرة واحدة، لذلك يجب إجراء التعيين على أجزاء، ومعالجة جزء صغير في كل مرة.
دعونا نلقي نظرة على بعض الوظائف أولا
CreateFile: فتح ملف
GetFileSize: احصل على حجم الملف
CreateFileMapping: إنشاء الخرائط
MapViewOfFile: ملف التعيين
بالنظر إلى مساعدة MapViewOfFile، يجب أن تكون المعلمتان الأخيرتان عددًا صحيحًا مضاعفًا لدقة الصفحة بشكل عام، تبلغ دقة الصفحة للجهاز 64 كيلو بايت (65536 بايت)، ومع ذلك، في عمليتنا الفعلية، هذا ليس هو الحال بشكل عام أي موضع، أي طول ممكن، لذلك يجب إجراء بعض المعالجة.
مهمة هذا المثال هي قراءة قيم الطول بالتسلسل من قائمة الطول (FInfoList)، ثم قراءة بيانات الطول المحدد بالتسلسل من ملف آخر كبير (FSourceFileName). إذا كان ملفًا صغيرًا، فهذا أسهل للتعامل معها، ما عليك سوى قراءة تدفق الملف مرة واحدة ثم قراءته بالتسلسل، بالنسبة للملفات الكبيرة، نحتاج إلى تغيير موضع التعيين باستمرار للحصول على البيانات التي نريدها.
يوضح هذا المثال أنه يتم الحصول على دقة الصفحة أولاً من خلال GetSystemInfo، ثم يتم استخدام دقة الصفحة ككتلة بيانات معينة في حلقة for، وسيتم الحكم على ما إذا كان طول القراءة (الإجمالي) بالإضافة إلى الطول المراد قراءته ضمن هذه المرة ضمن نطاق التعيين (10 أضعاف دقة الصفحة)، إذا كان كذلك، فاستمر في القراءة. إذا تم تجاوزه، فيجب تسجيل البيانات المتبقية، ثم يجب إعادة تعيين الكتلة التالية من الذاكرة، ويجب دمج البيانات المتبقية المسجلة. في القراءة الجديدة، البيانات التي تم الحصول عليها معقدة بعض الشيء (ربما تكون فكرتي معقدة للغاية)،
الرمز مدرج أدناه.
الإجراء TGetDataThread.DoGetData; var FFile_Handle:THandle; FFile_Map:THandle; TMemoryStream.Create list := TStringList.Create; // الحصول على معلومات النظام GetSystemInfo(sysinfo); // دقة تخصيص الصفحة blockize := sysinfo.dwAlllocationGranularity; // فتح الملف FFile_Handle := CreateFile(PChar(FSourceFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); FFile_Handle = INVALID_HANDLE_VALUE ثم اخرج؛ // احصل على حجم الملف := GetFileSize(FFile_Handle,nil); // إنشاء تعيين FFile_Map := CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil); // هنا قمنا بتعيين حجم كتلة 10 مرات في كتلة بيانات واحدة إذا كان حجم الملف أقل من 10 أضعاف حجم الكتلة، فسيتم تعيين طول الملف بالكامل مباشرة إذا كان حجم الملف div > 10 ثم readlen := 10*blocksize else readlen :=. حجم الملف: = 0 إلى FInfoList.Count - 1 يبدأ القائمة.Delimiter := ':' list.DelimitedText := FInfoList.Strings[i]; // احصل على الطول، لقد قمت بالتحليل هنا، لأن المعلومات التي قمت بتخزينها هي من النوع a:b:c، لذلك يتم فصل len بواسطة ::= StrToInt(list.Strings[1]);فاصل زمني := StrToInt(list .Strings[2])؛ إذا (i = 0) أو (totallen+len >=readlen) ثم ابدأ // إذا كان طول القراءة بالإضافة إلى الطول المراد قراءته أكبر من 10 أضعاف حجم الكتلة، فسنحتاج إلى الاحتفاظ بالمحتوى في نهاية التعيين السابق لدمجه مع محتوى التعيين الجديد إذا كنت > 0 ثم نبدأ Offset := offset + readlen ; // اكتب في الدفق المؤقت tstream.Write(p^,readlen-totallen); tstream.Position := 0; // إذا كان طول البيانات غير المقروءة غير كافٍ لتخصيص واحد التفاصيل، ثم قم بتعيين الطول المتبقي مباشرة إذا كان إزاحة حجم الملف < حجم الكتلة readlen := PNG-offset; // Mapping, p هو مؤشر لمنطقة التعيين // لاحظ أن المعلمة الثالثة هنا يتم تعيينها دائمًا على 0. يجب تعيين هذه القيمة وفقًا للموقف الفعلي p:= PChar(MapViewOfFile( FFile_Map,FILE_MAP_READ, 0,offset,readlen)); // إذا كانت هناك بيانات في الدفق المؤقت، فيجب دمجها إذا بدأ tstream.Size > 0 // انسخ بيانات الدفق المؤقتة عبرstream.CopyFrom(tstream,tstream.Size); // ثم اكتب بيانات جديدة في النهاية وادمجها لإكمال الدفق.Write(p^,len-tstream.Size); - tstream.Size // حرك موضع المؤشر للإشارة إلى بداية البيانات التالية Inc(p,len-tstream.Size); الإجمالي := الإجمالي + len Inc(p,len); end; Free؛ CloseHandle(FFile_Handle);
إذا كان لديك أي أسئلة، يرجى ترك رسالة أو الذهاب إلى مجتمع هذا الموقع للتواصل والمناقشة. شكرًا لك على القراءة، وآمل أن تتمكن من مساعدة الجميع. شكرًا لك على دعمك لهذا الموقع.