كيفية استخدام جافا سكريبت لحزم الملفات في حزمة مضغوطة (.zip)

9 مارس 2025

في تطوير الويب الحديث، يعد ضغط الملفات متطلبًا شائعًا. قد يحتاج المستخدمون إلى دمج ملفات متعددة في حزمة مضغوطة للتنزيل، أو إنشاء ملفات من خلال تطبيق ويب وتصديرها كملف .zip. ستقدم هذه المدونة دليلاً مفصلاً حول كيفية تنفيذ عمليات حزم وضغط الملفات في المتصفح باستخدام جافا سكريبت. سنقوم بذلك باستخدام مكتبة جافا سكريبت الشهيرة JSZip والاستفادة من FileSaver.js لتنزيل الملفات.

التحضير

أولاً، نحتاج إلى تثبيت مكتبتين شائعتي الاستخدام:

  1. JSZip: هذه مكتبة جافا سكريبت خفيفة الوزن تستخدم لإنشاء ومعالجة ملفات .zip.
  2. FileSaver.js: توفر هذه المكتبة طريقة متوافقة مع مختلف المتصفحات لتفعيل تنزيل الملفات.

يمكنك تثبيت هذه المكتبات في مشروعك باستخدام:

npm install jszip file-saver

أو تضمينها عبر CDN (للاستخدام في HTML):

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/FileSaver.min.js"></script>

تنفيذ دالة المساعدة

بعد ذلك، سنكتب دالة مساعدة مغلفة لحزم ملفات متعددة في ملف .zip وتفعيل التنزيل. لنفترض أننا نريد حزم سلسلة من الصور، والتي يمكن أن تكون ملفات أصلية أو ملفات معالجة.

دالة downloadFilesAsZip العامة

import JSZip from "jszip";
import { saveAs } from "file-saver";

/**
 * تنزيل ملفات متعددة محزومة كملف Zip
 * @param {Array} files - مصفوفة من كائنات الملفات، كل منها يحتوي على عنوان URL واسم ملف
 * @param {string} zipName - اسم ملف Zip المُنشأ، الافتراضي هو 'download.zip'
 */
export const downloadFilesAsZip = async (files, zipName = "download.zip") => {
  // إنشاء نسخة جديدة من JSZip
  const zip = new JSZip();

  // استخدام map لإنشاء مصفوفة من الوعود لمعالجة كل ملف
  const fetchPromises = files.map(async (file) => {
    try {
      // طلب مورد الملف، بافتراض أن الملف مقدم عبر URL
      const response = await fetch(file.url); // الحصول على مورد الملف
      const blob = await response.blob(); // تحويل الاستجابة إلى كائن Blob

      // إضافة الملف إلى حزمة zip، باستخدام اسم الملف المقدم
      zip.file(file.name, blob);
    } catch (error) {
      console.error(`فشل في إضافة الملف: ${file.name}`, error);
    }
  });

  // انتظار تنزيل جميع الملفات وإضافتها إلى Zip
  await Promise.all(fetchPromises);

  // توليد محتوى حزمة zip (نوع blob)
  const content = await zip.generateAsync({ type: "blob" });

  // استخدام FileSaver.js لتنزيل حزمة zip
  saveAs(content, zipName);
};

شرح الكود

  • إنشاء نسخة من JSZip: const zip = new JSZip(); — ينشئ نسخة جديدة من ملف Zip، ستتم إضافة جميع الملفات إلى هذه النسخة.
  • تنزيل وحزم الملفات: يستخدم دالة fetch() للحصول على محتوى الملف من URL، ثم يحوله إلى تنسيق blob. هذا لأن JSZip يدعم معالجة الملفات بتنسيق blob.
  • توليد ملف .zip: من خلال zip.generateAsync({ type: "blob" })، يتم ضغط جميع الملفات المضافة إلى كائن zip في ملف .zip، مما يعيد كائن blob.
  • حفظ الملف: باستخدام saveAs(content, zipName) مع FileSaver.js لتفعيل تنزيل الملف، حيث content هو حزمة zip المُنشأة وzipName هو اسم ملف التنزيل.

كيفية استخدام دالة المساعدة هذه

لنفترض أن لدينا مجموعة من عناوين URL للصور ونريد حزمها في ملف .zip للتنزيل. إليك مثالاً على كيفية استدعاء دالة downloadFilesAsZip:

// بيانات ملف مثال: تحتوي على URL الملف واسم الملف
const files = [
  { url: "https://example.com/image1.jpg", name: "image1.jpg" },
  { url: "https://example.com/image2.jpg", name: "image2.jpg" },
  { url: "https://example.com/image3.jpg", name: "image3.jpg" },
];

// استدعاء الدالة لتنزيل الملفات وحزمها كملف zip
downloadFilesAsZip(files, "images.zip");

في هذا المثال، نقدم مصفوفة من الكائنات التي تحتوي على عناوين URL للصور وأسماء الملفات. بعد استدعاء دالة downloadFilesAsZip، سيقوم المتصفح تلقائيًا بتفعيل عملية تنزيل وحزم هذه الصور في ملف مضغوط يسمى images.zip.

المشاكل الشائعة والحلول

  1. مشاكل عبر المنشأ (Cross-Origin) إذا كانت الملفات تأتي من نطاقات مختلفة، تأكد من أن الخادم قد ضبط رؤوس مشاركة الموارد عبر المنشأ (CORS) بشكل صحيح. وإلا، سيحظر المتصفح طلبات fetch()، مما يمنع تنزيل الملفات.
  2. تنزيل ملفات كبيرة إذا كانت الملفات التي يتم تنزيلها كبيرة، قد تحتاج إلى تحسين عملية التنزيل، مثل تنفيذ تنزيلات مجزأة أو عرض أشرطة تقدم.
  3. دعم المتصفح تعتمد هذه الطريقة على fetch() وFileSaver.js، لذا فهي تتطلب متصفحات حديثة تدعم هذه الواجهات البرمجية. إذا كنت بحاجة إلى دعم متصفحات أقدم، فكر في استخدام polyfills.

الحلول البديلة

بالإضافة إلى استخدام JSZip وFileSaver.js، هناك العديد من الحلول الشائعة الأخرى لتنفيذ ضغط وحزم الملفات في المتصفح:

  1. Pako.js: Pako هي مكتبة ضغط zlib لجافا سكريبت، تدعم تنسيقات gzip وdeflate. وهي مناسبة لضغط الملفات الأصغر وسهلة الاستخدام نسبيًا.
  2. Archiver.js: Archiver.js هي مكتبة غنية بالميزات تدعم الضغط إلى تنسيقات مثل .tar، .zip، إلخ. يمكنها تنفيذ ضغط الملفات في المتصفح وتوفر المزيد من خيارات التحكم.
  3. zip.js: zip.js هي مكتبة جافا سكريبت تدعم فك الضغط والضغط المتدفق، قادرة على التعامل مع ملفات أكبر وتوفير وظائف للضغط إلى ملفات .zip.
  4. BrowserFS + zip-lib: BrowserFS هي مكتبة توفر محاكاة لنظام الملفات في المتصفح. عند دمجها مع zip-lib، يمكنها إنشاء وتنزيل ملفات .zip، مناسبة للتطبيقات التي تحتاج إلى محاكاة نظام ملفات.