zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    jdk1.8安装与配置
    java编译器——idea的安装
    原型设计作业
    案例分析作业
    202103226-1 编程作业
    阅读任务
    准备工作
    java课程总结
    第十四周总结
    第十三周总结
  • 原文地址:https://www.cnblogs.com/ogurayui/p/13528893.html
Copyright © 2011-2022 走看看