الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

درس: ضغط وفك ضغط الملفات برمجيا

بدأه Mohammad Elsheimy في 15 يوليو 2009 · 6 رد · 2,926 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

قمت بكتابة هذا الدرس سابقا في موقعي
.

نظرة خاطفة

هذا الدرس يركز على كيفية ضغط وفك ضغط الملفات برمجيا في بيئة الدوت نت. سوف نقوم بداية بشرح آليات الضغط التي توفرها لنا بيئة الدوت نت. ثم سوف نقوم بعد ذلك بتطبيق الأفكار التي تعلمناها.

مقدمة

توفر لك بيئة الدوت نت إمكانيات للتعامل مع اثنان فقط من آليات الضغط الموجودة حاليا ولكنهما اثنان من أقوى وأشهر الآليات الموجودة الآن. وهذان الاثنان هما:

  • Deflate:
    هذه الآلية تعتبر من الآليات البسيطة جدا ويفضل عدم استخدامها إلا إذا كنت لا تنوي استعمالها إلا في برنامجك فقط وذلك لأن الملفات المضغوطة بهذه الآلية لا يمكن فكها ببرامج ضغط الملفات المعروفة مثل WinRAR و WinZip وذلك لأن هذه الآلية لا تقوم بإضافة البيانات Headers التي تساعد برامج ضغط الملفات على فكها وبالتالي فلا تستطيع هذه البرامج التعامل معها. وأيضا بسبب أن هذه الآلية لا تقوم بإضافة بيانات Headers إلى الملفات المضغوطة فإن الملفات المضغوطة يصبح حجمها أقل من الملفات المضافة إليها هذه البيانات.
  • GZIP:
    تعتبر هذه الآلية أفضل من سابقتها. بجانب أن هذه الآلية تقوم بإضافة بيانات Headers إلى الملفات المضغوطة والذي يسمح لبرامج الضغط بالتعامل معها، لهذه الآلية ميزة عظيمة جدا وهي أنها تقوم بعمل فحص Check للبيانات حتى لا تتعرض للتلف أثناء ضغطها أو فكها بعكس الآلية السابقة.

لمعرفة المزيد من التفاصيل حول آلية GZIP اقرأ
.

لحسن الحظ أنه في بيئة الدوت نت طريقة التعامل مع هاتين الآليتين هي نفسها بالضبط ولا يوجد اختلاف غير أنك تقوم بتغيير اسماء الأنواع Classes فقط. فبيئة الدوت توفر لك جميع الأنواع Classes التي تحتاجها في الـ Namespace المسمى بـ System.IO.Compression وهو موجود في المكتبة System.dll ولهذا لا تحتاج إلى خطوات إضافية قبل التعامل مع الكود. هذه الـ Namespace المسماة بـ System.IO.Compression تحتوي على الأنواع التي تحتاجها لضغط وفك ضغط الملفات وهي -لحسن الحظ- ثلاثة أنواع فقط وهي:

  • DeflateStream:
    وهذا النوع يمثل آلية Deflate.
  • GZipStream:
    وهذا النوع يمثل الآلية GZIP.
  • CompressionMode:
    وهذه Enumeration تحدد نوع العملية إما ضغط Compress أو فك ضغط Decompress.

وكما ذكرنا سابقا أن سواء تعاملك مع آلية Deflate بواسطة العنصر DeflateStream أو الآلية الأخرى لا يوجد فرق في التعامل غير أنك إذا أردت التعامل مثلا مع آلية GZIP تقوم بتغيير اسم العنصر إلى GZipStream والعكس بالعكس.

ضغط ملف

الكود التالي يوضح كيفية ضغط ملف وهو كود بسيط وسهل جدا ولا يحتاج إلى شرح. يقوم هذا الكود بضغط الملف D:\My Great Word Document.doc ليصبح ملفا مضغوطا D:\CompressedGreatDocument.zip. بالطبع يمكنك تغيير أسماء الملفات إلى الملفات التي تريدها.

قبل تنفيذ هذه الكود يجب عليك إضافة أمرين using (في C#) أو Imports (في VB.NET) للـ Namespaces المطلوبة وهي System.IO و System.IO.Compression.

// C# Code

string fileToBeCompressed = "D:\\My Great Word Document.doc";
string zipFilename = "D:\\CompressedGreatDocument.zip";

FileStream target = new FileStream(zipFilename, FileMode.Create, FileAccess.Write);
GZipStream alg = new GZipStream(target, CompressionMode.Compress);

byte[] data = File.ReadAllBytes(fileToBeCompressed);
alg.Write(data, 0, data.Length);
alg.Flush();

-------------------------------

// VB.NET Code

Dim fileToBeCompressed As String = "D:\\My Great Word Document.doc"
Dim zipFilename As String = "D:\\CompressedGreatDocument.zip"

Dim target As New FileStream(zipFilename, FileMode.Create, FileAccess.Write)
Dim alg As New GZipStream(target, CompressionMode.Compress)

Dim data() As Byte = File.ReadAllBytes(fileToBeCompressed)
alg.Write(data, 0, data.Length)
alg.Flush()

إذا كنت تريد ضغط ملف يجب عليك تحديد CompressionMode.Compress ويتم الضغط باستخدام الدالة Write وأيضا يجب عليك فتح الملف الذي يجب الكتابة فيه.

مرة أخرى، إذا كنت تريد استخدام الآلية Deflate فقط قم بتغيير اسم النوع Class إلى DeflateStream.

فك ضغط ملف

يقوم الكود التالي بفك ضغط الملف الذي قمنا بضغطه سابقا.

// C# Code

string compressedFile = "D:\\CompressedGreatDocument.zip";
string originalFileName = "D:\\My Great Word Document.doc";

FileStream zipFile = new FileStream(compressedFile, FileMode.Open, FileAccess.Read);
FileStream originalFile = new FileStream(originalFileName, FileMode.Create, FileAccess.Write);
GZipStream alg = new GZipStream(zipFile, CompressionMode.Decompress);

while (true)
{
// قراءة 100 بايت في كل مرة
byte[] buffer = new byte[100];
// تقوم الدالة التالية بإعطائنا عدد البايتات التي تمت قراءتها
int bytesRead = alg.Read(buffer, 0, buffer.Length);
originalFile.Write(buffer, 0, bytesRead);
if (bytesRead != buffer.Length)
break;
}

-------------------------------

' VB.NET Code

Dim compressedFile As String = "D:\\CompressedGreatDocument.zip"
Dim originalFileName As String = "D:\\My Great Word Document.doc"

Dim zipFile As New FileStream(compressedFile, FileMode.Open, FileAccess.Read)
Dim originalFile As New FileStream(originalFileName, FileMode.Create, FileAccess.Write)
Dim alg As New GZipStream(zipFile, CompressionMode.Decompress)

While (True)
' قراءة 100 بايت في كل مرة
Dim buffer(100) As Byte
' تقوم الدالة التالية بإعطائنا عدد البايتات التي تمت قراءتها
Dim bytesRead As Integer = _
alg.Read(buffer, 0, buffer.Length)

originalFile.Write(buffer, 0, bytesRead)

If (bytesRead <> buffer.Length) Then
Exit While
End If
End While

قمنا بإنشاء عنصري FileStream الأول للقراءة من الملف المضغوط والثاني للكتابة فيه أي للفك إليه. ثم قمنا بالقراءة من الملف المضغوط في كل مرة 100 بايت وفك هذه البيانات وكتابتها في الملف المفكوك. وهكذا.

للتدريب

جرب إنشاء برنامج يقوم بضغط الملفات مثل برنامج WinRAR مثلا. يمكنك الاعتماد على الأنواع BinaryReader و BinaryWriter للتعامل الدقيق مع الملفات.

خاتمة

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

تم تعديل هذه المشاركة بواسطة Mohammad Elsheimy في 15 يوليو 2009 في 17:24

#2

شكراً لك يا محمد ...... موضوع مهم

#3

جزاك الله أخى على كل ماتقدمه

 وممّا زادنـــي شرفــاً وتيهــاً   **  وكدت بأخمصي أطأ الثريّا

دخولي تحت قولك يا عبادي  **   وأن صيّرت أحمد لي نبيّـاً

#4

مشكور

الطريقة هاي قادرة على ضغط ملف واحد فقط أو فك ملف واحد .

رَبِّ أَوْزِعْنِي أَنْ أَشْكُرَ نِعْمَتَكَ الَّتِي أَنْعَمْتَ عَلَيَّ وَعَلَى وَالِدَيَّ وَأَنْ أَعْمَلَ صَالِحًا تَرْضَاهُ وَأَدْخِلْنِي بِرَحْمَتِكَ فِي عِبَادِكَ الصَّالِحِينَ

تلاوات خاشعة مؤثرة

#5

مشكور اخي محمد ،،

شخصيا استفدت من الموضوع فالامر جديد بالنسبة لي ،،

بالنسبة للدرس لم افهم كثيرا شرط التوقف في قراءة الملف المكبوس.

اقتباس
if (bytesRead != buffer.Length)

break;

اقتباس
في دروس أخرى بإذن الله تعالى نشرح كيفية تسجيل ملفات في قاعدة بيانات SQL Server.

في الانتظار ان شاء الله.

اقتباس
جرب إنشاء برنامج يقوم بضغط الملفات مثل برنامج WinRAR مثلا. يمكنك الاعتماد على الأنواع BinaryReader و BinaryWriter للتعامل الدقيق مع الملفات.

جميل ،، لما لا نعمل هذا البرنامج هنا في القسم؟

تم تعديل هذه المشاركة بواسطة الاخير زمانه في 17 يوليو 2009 في 15:40

/index.php/topic/264448-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF/

 

اني وان كنت الاخير زمانه ---- لأتِ بما لم تستطعه الاوائلُ

#6

شكرا ليك محمد بس انا ليه ملاحظه بسيطه بس انت المفروض تراعى قفل الاستريم filestream اللى انت فتحته فى اول الكود بعد انتهاء تنفيذ الكود حتى تستطيع اعاده استخدامه مره اخرى فى عمليه اخرى يعنى لو عملنا برنامج يضغط ويفك الضغط فى نفس البرنامج هيقولك file used by another process ومش هينفذ فلازم تضيف

target.Close();

والله اعلم الـ Gzip بيتقفل ولا لا انا معرفهاش دى بس اكيد بيتقفل برضوا لان اى استريم بيتفتح بيفتح الكونكشن للهارد ديسك لازم يتقفل وشكرا على مجهودك الرائع واسف على الطاله ...

تم تعديل هذه المشاركة بواسطة mohamed salmaa في 18 يوليو 2009 في 15:59

73b14eadba.gif

الحمدلله والصلاة والسلام على رسول الله وعلى آله وصحبه أجمعين

لكل مبتدئى البرمجه برمجه بلغه السى شارب

تنصيب ويندوز 8 على vmware

#7

السلام عليكم

أولا شكرا ليكم كلكم ولكل من مر على هذا الموضوع

بالنسبة للأخ سفيان

اقتباس
مشكور

الطريقة هاي قادرة على ضغط ملف واحد فقط أو فك ملف واحد .

فعلا الطريقة دي للعمل على ملف واحد ولكنك لو قرأت الجزء المسمى "للتدريب" ستجد طريقة للتعامل مع أكثر من ملف

بالنسبة للأخ "الأخير زمانه"

السطر

if (bytesRead != buffer.Length)
break;

طبعا المتغير bytesRead يحتوي على عدد البايتات التي تمت قراءتها. كل مرة نقوم بقراءة 100 بايت وهكذا. ولكن إذا كان في المرة الأخيرة العدد الذي قرأناه أقل من 100 بايت معنى هذا أنها كانت آخر بايتات في الملف وأننا انتهينا من قراءته فلهذا نقوم بإضافة الأمر break لأن لا نقوم بالقراءة مرة أخرى أي للخروج من الدوارة.

هتكون بجد فكرة كويسة إننا نعمل البرنامج ده هنا في المنتدى وانا فعلا فكرت في كده.

أخيرا

بالنسبة للأخ محمد سلامة

أنا قمت أولا بكتابة الدرس إنجليش في موقعي:

http://justlikeamagic.wordpress.com/2009/0...ecompress-files

ثم بعد ذلك قمت بترجمته للعربية في موقعي الآخر

http://withdotnet.wordpress.com/2009/07/15...ecompress-files

لو أخدت بالك هتلاقي إني بقفل الملف بالأصح بعملله Dispose بحطه في جملة using آخر استخدامه وهو ده الصح

بس بالنسبة للمتعلم

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

شكرا ليكم مرة تانية ولكل المارين على الدرس

مواضيع مشابهة