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

原文地址:https://www.cnblogs.com/ogurayui/p/13528893.html