• 【问题记录】 .Net 生成压缩文件问题


    一、起因

     由于公司开发项目需要迁移部署到Linux环境部署运行,之前项目中生成Zip压缩文件的代码逻辑在Linux运行生成压缩文件不正常。

     本篇记录文件排查处理过程。

    二、问题现象

    • 压缩文件生成目录不正确,文件目录为:\root\ziptest\upgrade\_dsconnCfg.txt(项目部署目录)
    • 压缩文件数量不正确
    • 压缩文件最后修改时间不匹配

     待压缩文件:

      

     压缩结果:

    三、解决过程:

     1、原始实现压缩的主要逻辑:

    using System.IO.Compression;
    using System.IO;
    /// <summary>
    /// 文件压缩类
    /// </summary>
    public class ZipHelper
    {
        /// <summary>
        /// 单文件压缩成ZIP
        /// </summary>
        /// <param name="fileSource">源文件路径</param>
        /// <param name="fileOut">ZIP文件路径</param>
        /// <param name="fileName">ZIP文件名</param>
        /// <returns></returns>
        public static bool SimpleFileZip(string fileSource, string fileOut, string fileName)
        {
            try
            {
                using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.Create))
                {
                    using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Create))
                    {
                        ZipFile(fileSource, fileName, archive);
                    }
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 多文件压缩成ZIP
        /// </summary>
        /// <param name="fileSource">源文件路径</param>
        /// <param name="fileOut">ZIP文件路径</param>
        /// <param name="fileName">ZIP文件名</param>
        /// <returns></returns>
        public static bool FilesZip(List<string> fileSources, string fileOut)
        {
            try
            {
                using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.Create))
                {
                    using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Create))
                    {
                        foreach (var file in fileSources)
                        {
                   //计算相对路径
    string fileName = file.Replace(AppConsts.ServerUpdateFile + "\\", ""); ZipFile(file, fileName, archive); } } } } catch { return false; } return true; } private static void ZipFile(string fileSource, string fileName, ZipArchive archive) { ZipArchiveEntry readMeEntry = archive.CreateEntry(fileName);
         //设置文件最后修改时间 readMeEntry.LastWriteTime
    = File.GetLastWriteTime(fileSource); using (Stream stream = readMeEntry.Open()) { byte[] bytes = File.ReadAllBytes(fileSource); stream.Write(bytes, 0, bytes.Length); } } }

     2、生成路径不正确问题:通过对代码检测发现,在代码中处理逻辑对目录路径替换处理时:使用了"\\";导致在Linux代码无效。修改对于代码为以下内容:

    /// <summary>
    /// 多文件压缩成ZIP
    /// </summary>
    /// <param name="fileSource">源文件路径</param>
    /// <param name="fileOut">ZIP文件路径</param>
    /// <param name="fileName">ZIP文件名</param>
    /// <returns></returns>
    public static bool FilesZip(List<string> fileSources, string fileOut)
    {
        try
        {
            using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Update))
                {
                    foreach (var file in fileSources)
                    {
                //计算压缩文件相对路径:目录/文件名 string fileName = file.Replace(AppConsts.ServerUpdateFile + Path.DirectorySeparatorChar, ""); ZipFile(file, fileName, archive); } } } } catch (Exception ex) { Console.WriteLine($"ERROR:{ex}"); return false; } return true; }

     3、排查生成文件数量异常问题,输出异常信息。

    ERROR:Cannot modify entry in Create mode after entry has been opened for writing.
       at System.IO.Compression.ZipArchiveEntry.set_LastWriteTime(DateTimeOffset value)
       at zlWebPluginsUpgradeServer.Upgrade.ZipHelper.ZipFile(String fileSource, String fileName, ZipArchive archive) in F:\coding\ZlsoftClientService\zlWebPluginsUpgradeServer\UpgradeMode\ZipHelper.cs:line 84
       at zlWebPluginsUpgradeServer.Upgrade.ZipHelper.FilesZip(List`1 fileSources, String fileOut) in F:\coding\ZlsoftClientService\zlWebPluginsUpgradeServer\UpgradeMode\ZipHelper.cs:line 62

      发现因为生成压缩文件后设置最后修改时间异常,导致生成压缩文件数量不正确;且最后修改时间不匹配。

     4、根据日志,调整

    using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Update))

      到此以上在Linux中生成压缩文件问题都已解决。

    四、总结:

     1、代码中路径操作,不要使用固定字符串;应该使用Path类提供的相关字段、方法操作

     2、设置压缩项属性时,需要使用Update模式。

    最后放上压缩帮助类:

    /// <summary>
    /// 文件压缩类
    /// </summary>
    public class ZipHelper
    {
        /// <summary>
        /// 单文件压缩成ZIP
        /// </summary>
        /// <param name="fileSource">源文件路径</param>
        /// <param name="fileOut">ZIP文件路径</param>
        /// <param name="fileName">ZIP文件名:相对路径</param>
        /// <returns></returns>
        public static void SimpleFileZip(string fileSource, string fileOut, string fileName)
        {
            using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Update))
                {
                    fileName = fileName.Trim(Path.DirectorySeparatorChar);
                    ZipFile(fileSource, fileName, archive);
                }
            }
        }
    
        /// <summary>
        /// 多文件压缩成ZIP
        /// </summary>
        /// <param name="fileSource">源文件路径</param>
        /// <param name="fileOut">ZIP文件路径</param>
        /// <param name="fileName">ZIP文件名</param>
        /// <returns></returns>
        public static void FilesZip(List<string> fileSources, string fileOut)
        {
            using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Update))
                {
                    foreach (var file in fileSources)
                    {
                        string fileName = file.Replace(AppConsts.ServerUpdateFile + Path.DirectorySeparatorChar, "");
                        ZipFile(file, fileName, archive);
                    }
                }
            }
        }
    
        /// <summary>
        /// 压缩指定文件夹
        /// </summary>
        /// <param name="sourceDirectory"></param>
        /// <param name="fileOut"></param>
        public static void DirectoryZip(string sourceDirectory, string fileOut)
        {
            string[] allFiles = Directory.GetFiles(sourceDirectory, "", SearchOption.AllDirectories);
            using (FileStream zipFileToOpen = new FileStream(fileOut, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Update))
                {
                    foreach (var file in allFiles)
                    {
                        //获取压缩文件相对目录
                        string fileName = file.Replace(sourceDirectory + Path.DirectorySeparatorChar, "");
                        ZipFile(file, fileName, archive);
                    }
                }
            }
        }
    
        /// <summary>
        /// 解压文件到指定目录
        /// </summary>
        /// <param name="upZipDirPath"></param>
        /// <param name="zipPath"></param>
        public static void UnZip(string upZipDirPath, string zipPath)
        {
            if (!Directory.Exists(upZipDirPath))
                Directory.CreateDirectory(upZipDirPath);
            using (FileStream zipFileToOpen = new FileStream(zipPath, FileMode.Open))
            {
                using (ZipArchive archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Read))
                {
                    archive.ExtractToDirectory(upZipDirPath);
                }
            }
        }
    
        /// <summary>
        /// 生成压缩文件
        /// </summary>
        /// <param name="fileSource">源文件</param>
        /// <param name="fileName">压缩文件相对目录</param>
        /// <param name="archive">压缩文件包</param>
        private static void ZipFile(string fileSource, string fileName, ZipArchive archive)
        {
            ZipArchiveEntry readMeEntry = archive.CreateEntry(fileName);
            readMeEntry.LastWriteTime = File.GetLastWriteTime(fileSource);
            using (Stream stream = readMeEntry.Open())
            {
                byte[] bytes = File.ReadAllBytes(fileSource);
                stream.Write(bytes, 0, bytes.Length);
            }
        }
    }
    View Code
  • 相关阅读:
    【BZOJ4566】[HAOI2016]找相同字符
    【BZOJ3238】[AHOI2013]差异
    【BZOJ4698】[SDOI2008]Sandy的卡片
    后缀数组(SA)总结
    【HDU3117】Fibonacci Numbers
    线性常系数齐次递推总结
    【HDU4565】So Easy!
    【BZOJ3144】[HNOI2013]切糕
    【BZOJ1070】[SCOI2007]修车
    【LOJ6433】【PKUSC2018】最大前缀和
  • 原文地址:https://www.cnblogs.com/cwsheng/p/15943183.html
Copyright © 2020-2023  润新知