This article is available in English too, check it out here.
نظرة خاطفة
هذا الدرس يركز على كيفية ضغط وفك ضغط الملفات برمجيا في بيئة الدوت نت. سوف نقوم بداية بشرح آليات الضغط التي توفرها لنا بيئة الدوت نت. ثم سوف نقوم بعد ذلك بتطبيق الأفكار التي تعلمناها.
مقدمة
توفر لك بيئة الدوت نت إمكانيات للتعامل مع اثنان فقط من آليات الضغط الموجودة حاليا ولكنهما اثنان من أقوى وأشهر الآليات الموجودة الآن. وهذان الاثنان هما:
- Deflate:
هذه الآلية تعتبر من الآليات البسيطة جدا ويفضل عدم استخدامها إلا إذا كنت لا تنوي استعمالها إلا في برنامجك فقط وذلك لأن الملفات المضغوطة بهذه الآلية لا يمكن فكها ببرامج ضغط الملفات المعروفة مثل WinRAR و WinZip وذلك لأن هذه الآلية لا تقوم بإضافة البيانات Headers التي تساعد برامج ضغط الملفات على فكها وبالتالي فلا تستطيع هذه البرامج التعامل معها. وأيضا بسبب أن هذه الآلية لا تقوم بإضافة بيانات Headers إلى الملفات المضغوطة فإن الملفات المضغوطة يصبح حجمها أقل من الملفات المضافة إليها هذه البيانات. - GZIP:
تعتبر هذه الآلية أفضل من سابقتها. بجانب أن هذه الآلية تقوم بإضافة بيانات Headers إلى الملفات المضغوطة والذي يسمح لبرامج الضغط بالتعامل معها، لهذه الآلية ميزة عظيمة جدا وهي أنها تقوم بعمل فحص Check للبيانات حتى لا تتعرض للتلف أثناء ضغطها أو فكها بعكس الآلية السابقة.
لمعرفة المزيد من التفاصيل حول آلية GZIP اقرأ GZIP File Format Specification.
لحسن الحظ أنه في بيئة الدوت نت طريقة التعامل مع هاتين الآليتين هي نفسها بالضبط ولا يوجد اختلاف غير أنك تقوم بتغيير اسماء الأنواع 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.