一、起因

 由于公司开发项目需要迁移部署到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);
        }
    }
}

到此这篇关于.Net 生成压缩文件问题记录(推荐)的文章就介绍到这了,更多相关.Net 压缩文件内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部