问题记录- .Net 生成压缩文件问题

Posted One To One

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了问题记录- .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);
        
    

 

以上是关于问题记录- .Net 生成压缩文件问题的主要内容,如果未能解决你的问题,请参考以下文章

★CTF:Python脚本记录

杂项收集,包括-发邮件二维码生成文件下载压缩导出excel

java文档打包成压缩包并且下载

在 VB.net 中解压缩文件 [关闭]

Linux 入门记录:十九Linux 包管理工具 RPM

JAVA实现zip压缩需要注意的问题