icsharpcode / SharpZipLib

#ziplib is a Zip, GZip, Tar and BZip2 library written entirely in C# for the .NET platform.
http://icsharpcode.github.io/SharpZipLib/
MIT License
3.72k stars 976 forks source link

Add folder, unable to decompress #883

Open Luohui109 opened 11 hours ago

Luohui109 commented 11 hours ago

Describe the bug

Version SharpZipLib. 1.3.3 I'm not sure that version 4 has this issue “Stored, but compressed != uncompressed”

Reproduction Code

No response

Steps to reproduce

Step 1: namespace SoluM.Utils.Zip { using ICSharpCode.SharpZipLib.Zip; using System.Collections; using System.IO; using System.Threading;

/// <summary>
/// ICSharpCode.SharpZipLib.Zip
/// </summary>
public class ZipHelper
{
    /// <summary>
    /// 缓存字节数
    /// </summary>
    private const int BufferSize = 1024;

    /// <summary>
    /// 压缩最小等级
    /// </summary>
    public const int CompressionLevelMin = 0;

    /// <summary>
    /// 压缩最大等级
    /// </summary>
    public const int CompressionLevelMax = 9;

    internal static int CheckCompressionLevel(int compressionlevel)
    {
        return compressionlevel < CompressionLevelMin ? CompressionLevelMin : compressionlevel > CompressionLevelMax ? CompressionLevelMax : compressionlevel;
    }

    public class FileEntry
    {
        /// <summary>
        /// 
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string FullName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string ZipEntryName { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public bool IsDirectory { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string Extension { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public long Length { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public bool ReadOnly { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public FileAttributes Attributes { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public DateTime CreationTime { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public DateTime LastAccessTime { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public DateTime LastWriteTime { get; set; }
    }

public static bool IsDiskOnly(string path) { bool result = false;

        if (!string.IsNullOrWhiteSpace(path) && (File.Exists(path) || Directory.Exists(path)))
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);

            result = directoryInfo.Root.FullName == directoryInfo.FullName;
        }

        return result;
    }

    public static bool HasDescendants(string path)
    {
        bool result = false;

        if (!string.IsNullOrWhiteSpace(path) && (File.Exists(path) || Directory.Exists(path)))
        {
            if (File.Exists(path))
            {
                result = true;
            }
            else if (Directory.Exists(path))
            {
                result = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Length > 0;
            }
        }

        return result;
    }
    public static List<FileEntry> GetFileEntry(string path, bool includedemptydir = true)
    {
        List<FileEntry> fileEntryList = new List<FileEntry>();

        FileEntry fileEntry;
        FileInfo fileInfo;
        DirectoryInfo directoryInfo;

        //校验待添加到压缩包的全路径文件或文件夹
        if (!string.IsNullOrWhiteSpace(path))
        {
            //
            if (path.EndsWith(@"\"))
            {
                path = path.Remove(path.LastIndexOf(@"\"));
            }

            if (File.Exists(path))
            {
                fileInfo = new FileInfo(path);
                fileEntry = new FileEntry();
                fileEntry.Name = fileInfo.Name;
                fileEntry.FullName = fileInfo.FullName;
                fileEntry.ZipEntryName = fileInfo.Name;
                fileEntry.IsDirectory = false;
                fileEntry.Extension = fileInfo.Extension;
                fileEntry.Length = fileInfo.Length;
                fileEntry.ReadOnly = fileInfo.IsReadOnly;
                fileEntry.Attributes = fileInfo.Attributes;
                fileEntry.CreationTime = fileInfo.CreationTime;
                fileEntry.LastAccessTime = fileInfo.LastAccessTime;
                fileEntry.LastWriteTime = fileInfo.LastWriteTime;
                fileEntryList.Add(fileEntry);
            }
            else if (Directory.Exists(path))
            {
                if (!IsDiskOnly(path))
                {
                    if (includedemptydir || HasDescendants(path))
                    {
                        string parentPath = Path.GetDirectoryName(path) + @"\";

                        if (parentPath.EndsWith(@":\\"))
                        {
                            parentPath = parentPath.Replace(@"\\", @"\");
                        }

                        //先将顶级文件夹压入
                        directoryInfo = new DirectoryInfo(path);
                        fileEntry = new FileEntry();
                        fileEntry.Name = directoryInfo.Name;
                        fileEntry.FullName = directoryInfo.FullName;
                        fileEntry.ZipEntryName = directoryInfo.FullName.Replace(parentPath, "");
                        fileEntry.IsDirectory = true;
                        fileEntry.Extension = "";
                        fileEntry.Length = 0;
                        fileEntry.ReadOnly = default;
                        fileEntry.Attributes = directoryInfo.Attributes;
                        fileEntry.CreationTime = directoryInfo.CreationTime;
                        fileEntry.LastAccessTime = directoryInfo.LastAccessTime;
                        fileEntry.LastWriteTime = directoryInfo.LastWriteTime;
                        fileEntryList.Add(fileEntry);

                        //再将其子孙文件、文件夹压入
                        //一次性获取下级所有目录,避免递归
                        string[] directories = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories);
                        foreach (string dir in directories)
                        {
                            if (includedemptydir || HasDescendants(dir))
                            {
                                directoryInfo = new DirectoryInfo(dir);
                                fileEntry = new FileEntry();
                                fileEntry.Name = directoryInfo.Name;
                                fileEntry.FullName = directoryInfo.FullName;
                                fileEntry.ZipEntryName = directoryInfo.FullName.Replace(parentPath, "");
                                fileEntry.IsDirectory = true;
                                fileEntry.Extension = "";
                                fileEntry.Length = 0;
                                fileEntry.ReadOnly = default;
                                fileEntry.Attributes = directoryInfo.Attributes;
                                fileEntry.CreationTime = directoryInfo.CreationTime;
                                fileEntry.LastAccessTime = directoryInfo.LastAccessTime;
                                fileEntry.LastWriteTime = directoryInfo.LastWriteTime;
                                fileEntryList.Add(fileEntry);
                            }
                        }
                        //一次性获取下级所有文件,避免递归
                        string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
                        foreach (string file in files)
                        {
                            fileInfo = new FileInfo(file);
                            fileEntry = new FileEntry();
                            fileEntry.Name = fileInfo.Name;
                            fileEntry.FullName = fileInfo.FullName;
                            fileEntry.ZipEntryName = fileInfo.FullName.Replace(parentPath, "");
                            fileEntry.IsDirectory = false;
                            fileEntry.Extension = fileInfo.Extension;
                            fileEntry.Length = fileInfo.Length;
                            fileEntry.ReadOnly = fileInfo.IsReadOnly;
                            fileEntry.Attributes = fileInfo.Attributes;
                            fileEntry.CreationTime = fileInfo.CreationTime;
                            fileEntry.LastAccessTime = fileInfo.LastAccessTime;
                            fileEntry.LastWriteTime = fileInfo.LastWriteTime;
                            fileEntryList.Add(fileEntry);
                        }
                    }
                }
            }
        }

        return fileEntryList;
    }
    public static List<FileEntry> GetFileEntry(IEnumerable<string> pathlist, bool includedemptydir = true)
    {
        List<FileEntry> fileEntryList = new List<FileEntry>();

        foreach (string path in pathlist)
        {
            fileEntryList.AddRange(GetFileEntry(path));
        }

        return fileEntryList;
    }

    public static string Compress(IEnumerable<string> sourcepathlist, string zipfilepath = null, string comment = null, string password = null, int compressionlevel = 6)
    {
        string result = null;

        try
        {
            //
            if (sourcepathlist == null || !(sourcepathlist.Count() > 0))
            {
                throw new Exception("待添加到压缩包的全路径文件或文件夹列表不能为空、NULL或空白字符!");
            }
            //
            foreach (string sourcepath in sourcepathlist)
            {
                if (string.IsNullOrWhiteSpace(sourcepath))
                {
                    throw new Exception("待添加到压缩包的全路径文件或文件夹列表中的元素不能为空、NULL或空白字符!");
                }

                if (!(File.Exists(sourcepath) || Directory.Exists(sourcepath)))
                {
                    throw new Exception($"待添加到压缩包的全路径文件或文件夹列表中元素[{sourcepath}]在存储设备上不存在!");
                }
            }

            //获取文件、文件夹列表
            List<FileEntry> fileEntryList = GetFileEntry(sourcepathlist);

            //检测目标文件夹是否存在,如果不存在则建立
            string zipFileDirectory = Path.GetDirectoryName(zipfilepath);
            if (!Directory.Exists(zipFileDirectory))
            {
                Directory.CreateDirectory(zipFileDirectory);
            }

            //创建压缩文件,若存在则覆盖
            using (FileStream zipStream = File.Create(zipfilepath))
            {
                using (ZipOutputStream zipOutputStream = new ZipOutputStream(zipStream))
                {
                    zipOutputStream.Password = password;//设置密码
                    zipOutputStream.SetComment(comment);//添加注释
                    zipOutputStream.SetLevel(CheckCompressionLevel(compressionlevel));//设置压缩等级

                    foreach (FileEntry fileEntry in fileEntryList)//从List取文件添加到压缩文件
                    {
                        if (fileEntry.IsDirectory)
                        {
                            ZipEntry zipEntry = new ZipEntry(fileEntry.ZipEntryName + @"\");
                            zipOutputStream.PutNextEntry(zipEntry);
                        }
                        else
                        {
                            using (FileStream fileStream = File.OpenRead(fileEntry.FullName))
                            {
                                ZipEntry zipEntry = new ZipEntry(fileEntry.ZipEntryName);
                                zipEntry.DateTime = fileEntry.LastWriteTime;
                                zipEntry.Size = fileEntry.Length;
                                zipOutputStream.PutNextEntry(zipEntry);

                                byte[] buffer = new byte[BufferSize];
                                int read = 0;
                                while ((read = fileStream.Read(buffer, 0, BufferSize)) > 0)
                                {
                                    zipOutputStream.Write(buffer, 0, read);
                                }
                            }
                        }
                    }

                    //
                    zipOutputStream.Flush();
                }
            }

            //
            result = zipfilepath;
        }
        catch (System.Exception ex)
        {
            if (File.Exists(zipfilepath))
            {
                File.Delete(zipfilepath);
            }
            throw new Exception("压缩失败!", ex);
        }

        return result;
    }

    public static string Decomparess(string zipfilepath, string destinationdirectory = null, string password = null)
    {
        string result = null;

        //
        if (string.IsNullOrWhiteSpace(zipfilepath))
        {
            throw new Exception("待解压缩文件[{zipfilepath}]不能为空、NULL或空白字符!");
        }
        //
        if (!File.Exists(zipfilepath))
        {
            throw new FileNotFoundException($"待解压缩文件[{zipfilepath}]在存储设备上不存在!");
        }

        //
        if (string.IsNullOrWhiteSpace(destinationdirectory))
        {
            FileInfo fileInfo = new FileInfo(zipfilepath);
            string directory = fileInfo.DirectoryName + @"\";
            string filename = fileInfo.Name.Substring(0, fileInfo.Name.Length - fileInfo.Extension.Length);

            destinationdirectory = directory + filename + @"\";
        }

        try
        {
            //
            if (!Directory.Exists(destinationdirectory))
            {
                Directory.CreateDirectory(destinationdirectory);
            }

            //
            using (FileStream zipFileStream = File.OpenRead(zipfilepath))
            {
                using (ZipInputStream zipInputStream = new ZipInputStream(zipFileStream))
                {
                    zipInputStream.Password = password;

                    ZipEntry zipEntry;
                    while ((zipEntry = zipInputStream.GetNextEntry()) != null)
                    {
                        //如果是文件夹则创建
                        if (zipEntry.IsDirectory)
                        {
                            Directory.CreateDirectory(Path.Combine(destinationdirectory, Path.GetDirectoryName(zipEntry.Name)));
                        }
                        //如果是文件则创建
                        else
                        {
                            string fileName = Path.GetFileName(zipEntry.Name);
                            if (!string.IsNullOrEmpty(fileName) && fileName.Trim().Length > 0)
                            {
                                FileInfo fileInfo = new FileInfo(Path.Combine(destinationdirectory, zipEntry.Name));

                                using (FileStream fileStream = fileInfo.Create())
                                {
                                    byte[] buffer = new byte[BufferSize];
                                    int read = 0;
                                    while ((read = zipInputStream.Read(buffer, 0, BufferSize)) > 0)
                                    {
                                        fileStream.Write(buffer, 0, read);
                                    }

                                    //
                                    fileStream.Flush();
                                }

                                //
                                fileInfo.LastWriteTime = zipEntry.DateTime;
                            }
                        }
                    }
                }
            }

            //
            result = destinationdirectory;
        }
        catch (System.Exception ex)
        {
            if (Directory.Exists(destinationdirectory))
            {
                Directory.Delete(destinationdirectory, true);
            }

            throw new Exception("解压缩发生错误!", ex);
        }

        return result;
    }

    public static string CompressAdd2(string zipfilepath, IEnumerable<string> sourcepathlist, string zipdirpath = null, string password = null)
    {
        string result = null;

        try
        {
            //
            if (string.IsNullOrWhiteSpace(zipfilepath))
            {
                throw new Exception("压缩文件[{zipfilepath}]不能为空、NULL或空白字符!");
            }
            //
            if (!File.Exists(zipfilepath))
            {
                throw new FileNotFoundException($"压缩文件[{zipfilepath}]在存储设备上不存在!");
            }

            //
            if (sourcepathlist == null || !(sourcepathlist.Count() > 0))
            {
                throw new Exception("待添加到压缩包的全路径文件或文件夹列表不能为空、NULL或空白字符!");
            }
            //
            foreach (string sourcepath in sourcepathlist)
            {
                if (string.IsNullOrWhiteSpace(sourcepath))
                {
                    throw new Exception("待添加到压缩包的全路径文件或文件夹列表中的元素不能为空、NULL或空白字符!");
                }

                if (!(File.Exists(sourcepath) || Directory.Exists(sourcepath)))
                {
                    throw new Exception($"待添加到压缩包的全路径文件或文件夹列表中元素[{sourcepath}]在存储设备上不存在!");
                }
            }

            //
            if (string.IsNullOrWhiteSpace(zipdirpath))
            {
                zipdirpath = null;
            }
            else
            {
                if (!zipdirpath.EndsWith(@"\"))
                {
                    zipdirpath = zipdirpath + @"\";
                }
            }

            //获取文件、文件夹列表
            List<FileEntry> fileEntryList = GetFileEntry(sourcepathlist);

            //将文件添加到已有zip文件中
            using (ZipFile zip = new ZipFile(zipfilepath))
            {
                //当前添加文件的密码,一个ZIP中,不同文件可以设置不同的密码
                //zip.Password = password;
                //更新压缩档的注释(全局)
                //zip.SetComment("1");

                zip.BeginUpdate();

                foreach (FileEntry fileEntry in fileEntryList)
                {
                    if (fileEntry.IsDirectory)
                    {
                        //zip.Add(new ZipEntry((zipdirpath != null ? zipdirpath : "") + fileEntry.ZipEntryName + @"\") { Size = 0, CompressedSize = 0, CompressionMethod = CompressionMethod.Deflated });
                        zip.AddDirectory((zipdirpath != null ? zipdirpath : "") + fileEntry.ZipEntryName + @"\");
                    }
                    else
                    {
                        //zip.Add(fileEntry.FullName, (zipdirpath != null ? zipdirpath : "") + fileEntry.ZipEntryName);
                        zip.Add(new StaticDataSource(fileEntry.FullName), new ZipEntry((zipdirpath != null ? zipdirpath : "") + fileEntry.ZipEntryName) { DateTime = fileEntry.LastWriteTime, Size = fileEntry.Length, CompressionMethod = CompressionMethod.Deflated });
                    }
                }
                zip.CommitUpdate();
            }

            //
            result = zipfilepath;
        }
        catch (System.Exception ex)
        {
            throw new Exception("压缩包添加文件失败!", ex);
        }

        return result;
    }
}

}

string[] filepaths = new string[] { @"C:\bill\d0d76d40-617b-496a-81e5-3105eae7b723.jpg", @"C:\bill\caf4e9b1-0232-4f0e-bf57-d31396ea73e9.jpg", @"C:\bill\tttt", @"C:\ball" };

Step 2: string zip = SoluM.Utils.Zip.ZipHelper.Compress(filepaths, null, "11111111111111", "123456"); Process.Start("explorer.exe", "/select, " + zip); string dezip = SoluM.Utils.Zip.ZipHelper.Decomparess(zip, @"C:\zipDe", "123456");

Step 3: string zip2 = SoluM.Utils.Zip.ZipHelper.CompressAdd(zippath3, new string[] { @"C:\bill\培训签到1.jpg", @"C:\bill\培训签到2.jpg", @"C:\bill\培训签到3.jpg", @"C:\HP_LaserJet_Pro_MFP_M426-M427" }, @"ball\1\2", null);

Step 4: SoluM.Utils.Zip.ZipHelper.Decomparess(zip2, null, "123456"); --Here,while ((zipEntry = zipInputStream.GetNextEntry()) != null),throw “Stored, but compressed != uncompressed”

Expected behavior

Fix the bug。

Operating System

Windows

Framework Version

.NET Framework 4.x

Tags

ZIP

Additional context

No response

SourceproStudio commented 11 hours ago

这是来自QQ邮箱的假期自动回复邮件。   您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。