العمل مع أرشيفات ZIP في TypeScript: مكتبة JSZip وأمثلة عملية
\n\nفي تطوير الويب الحديث، غالباً ما تنشأ الحاجة إلى ضغط عدة ملفات في أرشيف واحد لسهولة التحميل أو نقل البيانات. في بيئة TypeScript (و JavaScript)، الحل الأكثر شيوعاً للعمل مع أرشيفات ZIP هو مكتبة JSZip. تتيح لك إنشاء وقراءة وتعديل ملفات ZIP سواء في المتصفح أو في بيئة Node.js.
\n\nفي هذه المقالة، سنشرح بالتفصيل عملية التثبيت والإعداد والسيناريوهات الأساسية لاستخدام JSZip في مشاريع TypeScript. ستتعلم كيفية إنشاء أرشيفات من نصوص وبيانات ثنائية ومجلدات كاملة، بالإضافة إلى استخراج محتويات ملفات ZIP الموجودة.
\n\nتثبيت وإعداد JSZip
\n\nللبدء، قم بتثبيت المكتبة وأنواعها عبر npm أو yarn:
\n\nnpm install jszip\nnpm install --save-dev @types/jszip\n\nبعد التثبيت، قم باستيراد JSZip في ملف TypeScript الخاص بك:
\n\nimport JSZip from 'jszip';\n\nإذا كنت تستخدم نظام الوحدات (ES modules)، سيعمل الاستيراد كما هو موضح أعلاه. بالنسبة لـ CommonJS (require) قد يختلف الصياغة، ولكن في مشاريع TypeScript يُوصى باستيرادات ES.
إنشاء أرشيف ZIP جديد
\n\nالسيناريو الأبسط هو إنشاء أرشيف وإضافة عدة ملفات نصية إليه. لننظر إلى مثال:
\n\nconst zip = new JSZip();\n\n// إضافة ملفات نصية\nzip.file("hello.txt", "Hello, World!");\nzip.file("readme.md", "# وثائق\\n\\nهذا مثال لملف Markdown.");\n\n// إضافة مجلد وملف بداخله\nconst folder = zip.folder("images");\nfolder.file("logo.png", "base64encodedstring...", {base64: true});\n\n// إنشاء ملف ZIP كـ Blob\nzip.generateAsync({type: "blob"}).then((content) => {\n // إنشاء رابط للتحميل\n const link = document.createElement("a");\n link.href = URL.createObjectURL(content);\n link.download = "my-archive.zip";\n link.click();\n});\n\nفي هذا المثال قمنا بـ:
\n- \n
- إنشاء نسخة من
JSZip\n - إضافة ملفين نصيين باستخدام طريقة
.file()\n - إنشاء مجلد فرعي
imagesووضع ملف ببيانات base64 داخله \n - إنشاء الأرشيف بتنسيق Blob وبدء التحميل \n
قراءة واستخراج أرشيف ZIP موجود
\n\nتتيح JSZip ليس فقط إنشاء الأرشيفات، بل أيضاً قراءتها. لهذا الغرض يتم استخدام طريقة loadAsync():
async function readZipFile(zipBlob: Blob): Promise<void> {\n try {\n const zip = await JSZip.loadAsync(zipBlob);\n \n // الحصول على قائمة جميع الملفات\n const fileNames = Object.keys(zip.files);\n console.log("الملفات في الأرشيف:", fileNames);\n\n // استخراج محتوى ملف معين\n const helloFile = zip.file("hello.txt");\n if (helloFile) {\n const content = await helloFile.async("string");\n console.log("محتوى hello.txt:", content);\n }\n\n // التكرار عبر جميع الملفات\n zip.forEach((relativePath, zipEntry) => {\n console.log(`تم العثور على ملف: ${relativePath}, الحجم: ${zipEntry._data.uncompressedSize} بايت`);\n });\n\n } catch (error) {\n console.error("خطأ في قراءة ZIP:", error);\n }\n}\n\nلاحظ التحديد النوعي: JSZip.loadAsync() يُرجع وعداً (Promise) يتحول إلى كائن JSZip. طريقة .file() تُرجع JSZipObject | null، لذا قبل استدعاء .async() يجب التحقق من وجود الملف.
العمل مع البيانات الثنائية والصور
\n\nغالباً ما يكون مطلوباً ضغط الصور أو ملفات ثنائية أخرى في أرشيف. تدعم JSZip العمل مع ArrayBuffer و Blob و Uint8Array و base64:
\n\n// إضافة ملف من ArrayBu