C#打包文件到Zip


鑒於許多博客講C#打包Zip的都寫的相對啰嗦且沒有注釋,不適合小白觀看,特寫此篇講述一下

先貼代碼,直接創建一個.Net Core控制台就能運行

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;

namespace Zip
{
    class Program
    {
        static void Main(string[] args)
        {
            var zipFiles = new List<ZipFile>
            {
                new ZipFile
                {
                    RelativePath = "1/2/3/公文簽批單223.pdf",
                    Content = Extend.GetBytesFromPath("E:/公文簽批單.pdf")
                },
                new ZipFile
                {
                    RelativePath = "1/2/3/公文簽批單2233.pdf", //相同路徑下文件名重名時,解壓時會提示是否覆蓋
                    Content = Extend.GetBytesFromPath("E:/公文簽批單.pdf")
                }
            };

            var zipBytes = zipFiles.PackedZip();
            zipBytes.WriteToFile("E:/222/Zip測試.zip");
            Console.WriteLine("打包Zip成功");
            Console.ReadKey();
        }
    }

    public static class Extend
    {
        /// <summary>
        /// 將流轉成字節數組
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <returns></returns>
        public static byte[] ToBytes(this Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 設置當前流的位置為流的開始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// <summary>
        /// 獲取文件的內容(字節數組)
        /// </summary>
        /// <param name="absolutePath">絕對路徑</param>
        /// <returns></returns>
        public static byte[] GetBytesFromPath(string absolutePath)
        {
            using (Stream fileStream = new FileStream(absolutePath, FileMode.OpenOrCreate))
            {
                return fileStream.ToBytes();
            }
        }

        /// <summary>
        /// 字節數組寫入文件
        /// </summary>
        /// <param name="bytes">文件內容</param>
        /// <param name="absolutePath">絕對路徑</param>
        public static void WriteToFile(this byte[] bytes, string absolutePath)
        {
            if (File.Exists(absolutePath))
            {
                File.Delete(absolutePath);
            }

            using (var fs = new FileStream(absolutePath, FileMode.Create))
            {
                fs.Write(bytes, 0, bytes.Length);
            }
        }

        /// <summary>
        /// 將Zip文件描述對象打包成Zip文件,並返回字節數組
        /// </summary>
        /// <param name="zipFiles">Zip文件描述對象數組</param>
        /// <returns></returns>
        public static byte[] PackedZip(this List<ZipFile> zipFiles)
        {
            using (Stream memoryStream = new MemoryStream())
            {
                using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
                {
                    foreach (var zipFile in zipFiles)
                    {
                        zipArchive.AddFile(zipFile.RelativePath, zipFile.Content);
                    }
                }

                memoryStream.Seek(0, SeekOrigin.Begin); //這句要在using ZipArchive外面,否則壓縮文件會被損壞
                return memoryStream.ToBytes();
            }
        }

        /// <summary>
        /// 向Zip文件中添加文件
        /// </summary>
        /// <param name="zipArchive"></param>
        /// <param name="relativePath">相對路徑</param>
        /// <param name="bytes">文件內容</param>
        /// <returns></returns>
        private static bool AddFile(this ZipArchive zipArchive, string relativePath, byte[] bytes)
        {
            try
            {
                ZipArchiveEntry entry = zipArchive.CreateEntry(relativePath);
                using (Stream entryStream = entry.Open())
                {
                    entryStream.Write(bytes, 0, bytes.Length);
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
    }

    /// <summary>
    /// 描述打包成Zip時的一個文件的信息
    /// </summary>
    public class ZipFile
    {
        /// <summary>
        /// 文件相對路徑,帶文件名和拓展名
        /// </summary>
        public string RelativePath { get; set; }
        /// <summary>
        /// 字節數組(文件內容)
        /// </summary>
        public byte[] Content { get; set; }
    }
}
打包文件到Zip

打包時用的是.Net自帶ZipArchive類,此類在System.IO.Compression.dll的程序集的System.IO.Compression命名空間下,一般裝了VS都有,想用其他別的類庫操作Zip的可以上Nuget找,但筆者寫此文時用的最多就是這個

基本流程如下:
1、獲得文件流(示例代碼是用FileStream讀取物理文件),並把文件流轉成字節數組;(在操作文件流時,常用的橋接方式就是用字節數組,至少我們公司封裝的方法就是如此)【如上面代碼的GetBytesFromPath方法】

2、創建一個MemeryStream(內存流)對象,並用這個MemeryStream對象初始化ZipArchive對象(ZipArchive是.Net自帶的一個操作Zip的類)【如上面代碼的PackedZip方法】

p.s. 許多博客都用的物理文件初始化,那結果只能保存回那個物理文件,ZipArchive類本身不具備導出流對象的方法;但用流初始化呢,當對ZipArchive進行修改時都會同步到流對象,有了流對象就有了字節數組,我既可以保存回物理文件,也可以把流傳到網絡上任何地方

3、用ZipArchive對象創建ZipArchiveEntry對象,並打開ZipArchiveEntry對象的流,往流里寫入文件,這樣就相當於往這個Zip文件里面裝文件了,創建ZipArchiveEntry對象時使用的是相對路徑,文件夾不需要實際存在【如上面代碼的AddFile方法】
4、當裝填好Zip對象之后就把之前初始化ZipArchive對象的流轉成字節數組返回,至此就大功告成了,之后要導出到物理文件或網絡上都隨你


附錄,微軟官方的教程:

https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2012/june/clr-what%E2%80%99s-new-in-the-net-4-5-base-class-library


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM