العمل مع أرشيفات ZIP في Go (Golang)
في التطوير الحديث بلغة Go، غالبًا ما تنشأ الحاجة للعمل مع الأرشيفات — لتغليف السجلات، نشر الإعدادات، النسخ الاحتياطية أو نقل البيانات بين الخدمات المصغرة. توفر المكتبة القياسية للغة Go حزمة قوية ومرنة archive/zip، والتي تسمح بإنشاء وقراءة وتعديل أرشيفات ZIP دون تبعيات خارجية. في هذه المقالة، سنشرح بالتفصيل جميع جوانب العمل مع أرشيفات ZIP في Go.
نظرة عامة على حزمة archive/zip
حزمة archive/zip مضمنة في المكتبة القياسية للغة Go وتدعم:
- قراءة وكتابة أرشيفات ZIP (تنسيق PKWARE)
- الضغط بطريقة Deflate و Stored (بدون ضغط)
- العمل مع الملفات والمجلدات داخل الأرشيف
- دعم التعليقات للأرشيف والملفات الفردية
- تعيين سمات الملفات (التاريخ، صلاحيات الوصول)
- المعالجة التدفقية (يمكن أن تزن الأرشيفات غيغابايتات)
الأنواع الرئيسية: zip.Writer لإنشاء الأرشيفات و zip.Reader للقراءة.
إنشاء أرشيف ZIP
لإنشاء أرشيف، يُستخدم zip.NewWriter الذي يستقبل io.Writer. يتم إضافة كل ملف عبر Create أو CreateHeader.
package main
import ( "archive/zip" "bytes" "fmt" "io" "log" "os")
func main() { // إنشاء مخزن مؤقت للأرشيف buf := new(bytes.Buffer) writer := zip.NewWriter(buf)
// إضافة ملف نصي file1, err := writer.Create("hello.txt") if err != nil { log.Fatal(err) } _, err = file1.Write([]byte("Hello, Go ZIP!")) if err != nil { log.Fatal(err) }
// إضافة ملف مع مجلد فرعي file2, err := writer.Create("config/settings.json") if err != nil { log.Fatal(err) } _, err = file2.Write([]byte(`{"version": 1, "debug": true}`)) if err != nil { log.Fatal(err) }
// إغلاق الكاتب إلزاميًا err = writer.Close() if err != nil { log.Fatal(err) }
// حفظ الأرشيف على القرص err = os.WriteFile("example.zip", buf.Bytes(), 0644) if err != nil { log.Fatal(err) } fmt.Println("تم إنشاء الأرشيف: example.zip")}قراءة واستخراج الملفات من الأرشيف
لقراءة الأرشيف، يُستخدم zip.NewReader الذي يُمرر إليه io.ReaderAt وحجم الأرشيف. يمكن القراءة في الذاكرة أو بشكل تدفقي.
func readArchive() { // فتح ملف الأرشيف reader, err := zip.OpenReader("example.zip") if err != nil { log.Fatal(err) } defer reader.Close()
// التكرار عبر جميع الملفات في الأرشيف for _, file := range reader.File { fmt.Printf("الملف: %s (الحجم: %d بايت)", file.Name, file.UncompressedSize64)
// فتح الملف داخل الأرشيف rc, err := file.Open() if err != nil { log.Fatal(err) }
// قراءة المحتوى content, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } rc.Close()
fmt.Printf("المحتوى: %s
", content) }}إضافة ملفات مع بيانات وصفية
باستخدام zip.FileHeader يمكن تعيين التاريخ، صلاحيات الوصول وطريقة الضغط:
func addFileWithMetadata(w *zip.Writer, name, content string) error { header := &zip.FileHeader{ Name: name, Method: zip.Deflate, // استخدام Deflate (ضغط) } // تعيين وقت التعديل header.SetModTime(time.Now()) // تعيين صلاحيات الوصول (Unix rw-r--r--) header.SetMode(0644)
f, err := w.CreateHeader(header) if err != nil { return err } _, err = f.Write([]byte(content)) return