[C#] Zip 압축 코드 소스


Development note/C#  2019. 6. 3. 23:44

안녕하세요. 명월입니다.


이 글은 꽤 오래전에 작성한 포스팅입니다만, 개선된 내용이 있어 처음부터 다시 작성합니다.

Zip 압축 알고리즘은 많은 압축 알고리즘 중에서 가장 많이 사용되는 압축 알고리즘입니다. 알고리즘의 우수성도 우수성이지만 많은 라이브러리가 있어서 사용자들이 가장 쉽게 사용하는 듯합니다.

C# 내부에서도 Zip 알고리즘 라이브러리가 있습니다. 그 중 두가지 패턴이 있는데 하나는 오픈 소스 Ionic 라이브러리를 통해 압축, 해제하는 방법과 .Net Framework 내부 라이브러리를 이용해 압축, 해제하는 두 가지 방법이 있습니다. 두 라이브러리의 성능은 큰 차이는 없고 소스 스탭도 크게 차이가 없기 때문에 유저가 편하게 사용하고 싶은 거로 골라 사용하면 되겠습니다.


먼저 Ionic 라이브러리를 통해 압축하는 방법을 소개하겠습니다.

먼저 Visual studio에서 Nuget을 이용해 Ionic 라이브러리를 연결합니다.

다음에는 소스를 작성하겠습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Ionic.Zip;

namespace CS_ZipCompressSource
{
    class Program
    {
        /// <summary>
        /// 디렉토리내 파일 검색
        /// </summary>
        /// <param name="rootPath"></param>
        /// <param name="fileList"></param>
        /// <returns></returns>
        public static List<String> GetFileList(String rootPath, List<String> fileList)
        {
            if (fileList == null)
            {
                return null;
            }
            var attr = File.GetAttributes(rootPath);
            // 해당 path가 디렉토리이면
            if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
            {
                var dirInfo = new DirectoryInfo(rootPath);
                // 하위 모든 디렉토리는
                foreach (var dir in dirInfo.GetDirectories())
                {
                    // 재귀로 통하여 list를 취득한다.
                    GetFileList(dir.FullName, fileList);
                }
                // 하위 모든 파일은
                foreach (var file in dirInfo.GetFiles())
                {
                    // 재귀를 통하여 list를 취득한다.
                    GetFileList(file.FullName, fileList);
                }
            }
            // 해당 path가 파일이면 (재귀를 통해 들어온 경로)
            else
            {
                var fileInfo = new FileInfo(rootPath);
                // 리스트에 full path를 저장한다.
                fileList.Add(fileInfo.FullName);
            }
            return fileList;
        }
        /// <summary>
        /// Ionic 라이브러리로 압축하기
        /// </summary>
        /// <param name="sourcePath"> 압축 경로</param>
        /// <param name="zipPath"> 압축 파일 경로</param>
        public static void CompressZipByIonic(string sourcePath, string zipPath)
        {
            var filelist = GetFileList(sourcePath, new List<String>());
            using (var zip = new Ionic.Zip.ZipFile())
            {
                foreach (string file in filelist)
                {
                    string path = file.Substring(sourcePath.Length + 1);
                    zip.AddEntry(path, File.ReadAllBytes(file));
                }
                zip.Save(zipPath);
            }
        }
        static void Main(string[] args)
        {
            CompressZipByIonic(@"D:\work\CompressTest", @"D:\work\CompressTest\Ionic.zip");
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
}

예제 파일을 준비하고 실행시켜 봅니다.

위 이미지처럼 압축이 되었습니다.


이번에는 내부 라이브러리를 이용해서 압축, 해제하겠습니다.

먼저 System.IO.Commpress와 System.io.Comppression.FileSystem을 추가합니다.

그리고 다음과 같이 소스를 작성했습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Compression;

namespace CS_ZipCompressSource
{
    class Program
    {
        /// <summary>
        /// 디렉토리내 파일 검색
        /// </summary>
        /// <param name="rootPath"></param>
        /// <param name="fileList"></param>
        /// <returns></returns>
        public static List<String> GetFileList(String rootPath, List<String> fileList)
        {
            if (fileList == null)
            {
                return null;
            }
            var attr = File.GetAttributes(rootPath);
            // 해당 path가 디렉토리이면
            if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
            {
                var dirInfo = new DirectoryInfo(rootPath);
                // 하위 모든 디렉토리는
                foreach (var dir in dirInfo.GetDirectories())
                {
                    // 재귀로 통하여 list를 취득한다.
                    GetFileList(dir.FullName, fileList);
                }
                // 하위 모든 파일은
                foreach (var file in dirInfo.GetFiles())
                {
                    // 재귀를 통하여 list를 취득한다.
                    GetFileList(file.FullName, fileList);
                }
            }
            // 해당 path가 파일이면 (재귀를 통해 들어온 경로)
            else
            {
                var fileInfo = new FileInfo(rootPath);
                // 리스트에 full path를 저장한다.
                fileList.Add(fileInfo.FullName);
            }
            return fileList;
        }
        /// <summary>
        /// 내부 라이브러리로 압축하기
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="zipPath"></param>
        public static void CompressZipByIO(string sourcePath, string zipPath)
        {
            var filelist = GetFileList(sourcePath, new List<String>());
            using (FileStream fileStream = new FileStream(zipPath, FileMode.Create, FileAccess.ReadWrite))
            {
                using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create))
                {
                    foreach (string file in filelist)
                    {
                        string path = file.Substring(sourcePath.Length + 1);
                        zipArchive.CreateEntryFromFile(file, path);
                    }
                }
            }
        }
        static void Main(string[] args)
        {
            CompressZipByIO(@"D:\work\CompressTest", @"D:\work\CompressTest\IO.zip");
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
}

위에서 사용한 예제 파일을 이용해서 실행시켜 봅니다.

위와 같은 결과가 나왔습니다.


소스 내의 처리는 크게 다르지 않네요.

그러나 개인적으로 외부 오픈 소스보다는 내부 표준 라이브러리가 더 좋습니다. 오픈 소스는 혹여나 버그가 발생하면 대응하기가 쉽지 않아서 이죠.

참고 소스를 추가하겠습니다.

CS_ZipCompressSource.zip

링크 - [C#] Zip 압축 해제 코드 소스