타사 API를 사용하지 않고 C #으로 파일을 어떻게 압축합니까?


175

나는 이것이 복제본이 아니라고 확신하므로 잠시 동안 나와 함께하십시오.

타사 라이브러리를 사용하지 않고 프로그래밍 방식으로 파일을 어떻게 (C #) ZIP 파일로 만들 수 있습니까 (Windows)? 기본 윈도우 호출 또는 이와 유사한 것이 필요합니다. 나는 프로세스를 시작한다는 생각을 정말로 싫어하지만 절대적으로해야한다면. PInovke 전화가 훨씬 좋습니다.

실패하면 실제로 달성하려는 것을 말해 줄 것입니다. 사용자가 단일 요청으로 문서 모음을 다운로드 할 수있는 기능이 필요합니다. 이것을 달성하는 방법에 대한 아이디어가 있습니까?



1
@Chesso : 예, ASPX 페이지에서.
Esteban Araya 2016 년

1
몇 주 전에 같은 것을 검색 할 때이 예제가 유용하다는 것을 알았습니다. syntaxwarriors.com/2012/…
JensB

2
4.5 프레임 워크를 사용하는 경우 이제 ZipArchive 및 ZipFile 클래스가 있습니다.
GalacticJello

누구나 DotNetZip을 사용 했습니까?
핫 릭

답변:


85

.NET 3.5를 사용하고 있습니까? ZipPackage클래스와 관련 클래스를 사용할 수 있습니다 . 추가하는 각 파일에 대해 MIME 유형을 원하기 때문에 파일 목록을 압축하는 것 이상입니다. 원하는 것을 할 수 있습니다.

현재 비슷한 클래스를 사용하여 여러 관련 파일을 단일 파일로 아카이브하여 다운로드 할 수 있습니다. 파일 확장자를 사용하여 다운로드 파일을 데스크탑 앱과 연결합니다. 우리가 만난 작은 문제 중 하나는 클라이언트 측 코드가 열 수 없기 때문에 7-zip과 같은 타사 도구를 사용하여 zip 파일을 만들 수 없다는 것입니다. 컨텐츠 유형 파일이 누락 된 경우 각 구성 요소 파일 및 zip 파일을 열 수 없습니다.


1
오, 어떻게 당신을 사랑합니다! 감사합니다 브라이언; yuo는 우리에게 많은 두통과 $$$를 저장했습니다.
Esteban Araya 2016 년

6
항상 역순으로 작동하지는 않습니다. 일부 Zip 파일은 ZipPackage 클래스를 사용하여 재수 화되지 않습니다. ZipPackage로 만든 파일은 좋을 것입니다.
Craig

ZipPackage는 기존 압축 패키지에 추가 할 수 없습니다.
ΩmegaMan

한숨 : "유형 또는 네임 스페이스"Packaging "이 네임 스페이스"System.IO "에 없습니다
핫 릭

2
(위의 "한숨"에 대한 답변 : "참조"를 열고 "논리적으로 충분한" "WindowsBase"를 추가하십시오.
Hot Licks

307

타사 라이브러리를 사용하지 않고 프로그래밍 방식으로 파일을 어떻게 (C #) ZIP 파일로 만들 수 있습니까 (Windows)?

4.5+ 프레임 워크를 사용하는 경우 이제 ZipArchiveZipFile 클래스가 있습니다.

using (ZipArchive zip = ZipFile.Open("test.zip", ZipArchiveMode.Create))
{
    zip.CreateEntryFromFile(@"c:\something.txt", "data/path/something.txt");
}

다음에 대한 참조를 추가해야합니다.

  • System.IO.Compression
  • System.IO.Compression.FileSystem

net46을 대상으로하는 .NET Core의 경우 다음에 대한 종속성을 추가해야합니다.

  • System.IO.Compression
  • System.IO.Compression.ZipFile

예제 project.json :

"dependencies": {
  "System.IO.Compression": "4.1.0",
  "System.IO.Compression.ZipFile": "4.0.1"
},

"frameworks": {
  "net46": {}
}

.NET Core 2.0의 경우 간단한 using 문만 추가하면됩니다.

  • System.IO.Compression 사용;

4
이것이 어떻게 더 많은지지를 얻지 못했습니까? 유일한 대답입니다.
Matt Cashatt

12
이 질문은 5 세인 반면이 답변은 2 개월 밖에되지 않았습니다. Derp
:-P

3
@heliac 여전히 유래 거시기 질문하고 저장소에 응답하고 정신으로 최선의 대답은 상단에있을 shoudl한다 ... (젠장, 난이 일을하지 않는 것을 알고)
Offler

5
누군가에게 도움이되는 경우 두 번째 인수는 파일 항목입니다. 압축 해제 폴더를 기준으로 파일을 추출 할 경로입니다. Windows 7에서 파일 항목이 전체 경로 (예 : @ "D : \ Temp \ file1.pdf") 인 경우 기본 Windows 추출기가 실패 함을 발견했습니다. Directory.GetFiles ()에서 생성 된 파일 이름 만 사용하면이 문제가 발생할 수 있습니다. 파일 입력 인수에 Path.GetFileName ()을 사용하여 파일 이름을 추출하는 것이 가장 좋습니다.
Manish

2
4.5.2에서 이것을 찾을 수없는 것 같습니다.
user3791372

11

같은 상황에 있었고 타사 라이브러리 대신 .NET을 원했습니다. 위에서 언급 한 다른 포스터와 마찬가지로 ZipPackage 클래스 (.NET 3.5에서 도입)를 사용하는 것만으로는 충분하지 않습니다. ZipPackage가 작동하려면 아카이브에 반드시 포함되어야하는 추가 파일이 있습니다. 이 파일이 추가되면 Windows 탐색기에서 결과 ZIP 패키지를 직접 열 수 있습니다 (문제 없음).

[Content_Types] .xml 파일을 포함 할 모든 파일 확장자에 대해 "기본"노드를 사용하여 아카이브의 루트에 추가하기 만하면됩니다. 추가 한 후에는 Windows 탐색기에서 패키지를 찾아 보거나 프로그래밍 방식으로 압축을 풀고 내용을 읽을 수있었습니다.

[Content_Types] .xml 파일에 대한 자세한 내용은 여기를 참조하십시오 : http://msdn.microsoft.com/en-us/magazine/cc163372.aspx

다음은 [Content_Types] .xml (정확히 이름을 지정해야 함) 파일의 샘플입니다.

<?xml version="1.0" encoding="utf-8" ?>
<Types xmlns=
    "http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="xml" ContentType="text/xml" /> 
  <Default Extension="htm" ContentType="text/html" /> 
  <Default Extension="html" ContentType="text/html" /> 
  <Default Extension="rels" ContentType=
    "application/vnd.openxmlformats-package.relationships+xml" /> 
  <Default Extension="jpg" ContentType="image/jpeg" /> 
  <Default Extension="png" ContentType="image/png" /> 
  <Default Extension="css" ContentType="text/css" /> 
</Types>

ZIP 파일을 만들기위한 C # :

var zipFilePath = "c:\\myfile.zip"; 
var tempFolderPath = "c:\\unzipped"; 

    using (Package package = ZipPackage.Open(zipFilePath, FileMode.Open, FileAccess.Read)) 
    { 
        foreach (PackagePart part in package.GetParts()) 
        { 
            var target = Path.GetFullPath(Path.Combine(tempFolderPath, part.Uri.OriginalString.TrimStart('/'))); 
            var targetDir = target.Remove(target.LastIndexOf('\\')); 

            if (!Directory.Exists(targetDir)) 
                Directory.CreateDirectory(targetDir); 

            using (Stream source = part.GetStream(FileMode.Open, FileAccess.Read)) 
            { 
                source.CopyTo(File.OpenWrite(target)); 
            } 
        } 
    } 

노트 :


12
좋은 샘플이지만 ZIP 파일을 만들지 않습니다. 기존 파일을 압축 해제합니다.
매트 Varblow

9
    private static string CompressFile(string sourceFileName)
    {
        using (ZipArchive archive = ZipFile.Open(Path.ChangeExtension(sourceFileName, ".zip"), ZipArchiveMode.Create))
        {
            archive.CreateEntryFromFile(sourceFileName, Path.GetFileName(sourceFileName));
        }
        return Path.ChangeExtension(sourceFileName, ".zip");
    }

webapi 내부에 있고 HttpContext.Current.Request를 수신하면 어떻게 sourceFileName을 얻을 수 있습니까?
Olivertech

하나 이상의 파일을 압축 하시겠습니까?
Kiquenet

1

이 질문에 대한 Simon McKenzie의 답변 바탕 으로 다음 과 같은 방법을 사용하는 것이 좋습니다.

    public static void ZipFolder(string sourceFolder, string zipFile)
    {
        if (!System.IO.Directory.Exists(sourceFolder))
            throw new ArgumentException("sourceDirectory");

        byte[] zipHeader = new byte[] { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

        using (System.IO.FileStream fs = System.IO.File.Create(zipFile))
        {
            fs.Write(zipHeader, 0, zipHeader.Length);
        }

        dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
        dynamic source = shellApplication.NameSpace(sourceFolder);
        dynamic destination = shellApplication.NameSpace(zipFile);

        destination.CopyHere(source.Items(), 20);
    }

    public static void UnzipFile(string zipFile, string targetFolder)
    {
        if (!System.IO.Directory.Exists(targetFolder))
            System.IO.Directory.CreateDirectory(targetFolder);

        dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
        dynamic compressedFolderContents = shellApplication.NameSpace(zipFile).Items;
        dynamic destinationFolder = shellApplication.NameSpace(targetFolder);

        destinationFolder.CopyHere(compressedFolderContents);
    }
}

0

Windows 가이 작업을 수행 할 수있는 것처럼 보입니다 ...

불행히도 타사 구성 요소로 이동하지 않으면 별도의 프로세스를 시작하지 않을 것이라고 생각합니다.


0

다음 4 가지 기능을 프로젝트에 추가하십시오.

        public const long BUFFER_SIZE = 4096;
    public static void AddFileToZip(string zipFilename, string fileToAdd)
    {
        using (Package zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
        {
            string destFilename = ".\\" + Path.GetFileName(fileToAdd);
            Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
            if (zip.PartExists(uri))
            {
                zip.DeletePart(uri);
            }
            PackagePart part = zip.CreatePart(uri, "", CompressionOption.Normal);
            using (FileStream fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read))
            {
                using (Stream dest = part.GetStream())
                {
                    CopyStream(fileStream, dest);
                }
            }
        }
    }
    public static void CopyStream(global::System.IO.FileStream inputStream, global::System.IO.Stream outputStream)
    {
        long bufferSize = inputStream.Length < BUFFER_SIZE ? inputStream.Length : BUFFER_SIZE;
        byte[] buffer = new byte[bufferSize];
        int bytesRead = 0;
        long bytesWritten = 0;
        while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) != 0)
        {
            outputStream.Write(buffer, 0, bytesRead);
            bytesWritten += bytesRead;
        }
    }
    public static void RemoveFileFromZip(string zipFilename, string fileToRemove)
    {
        using (Package zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
        {
            string destFilename = ".\\" + fileToRemove;
            Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
            if (zip.PartExists(uri))
            {
                zip.DeletePart(uri);
            }
        }
    }
    public static void Remove_Content_Types_FromZip(string zipFileName)
    {
        string contents;
        using (ZipFile zipFile = new ZipFile(File.Open(zipFileName, FileMode.Open)))
        {
            /*
            ZipEntry startPartEntry = zipFile.GetEntry("[Content_Types].xml");
            using (StreamReader reader = new StreamReader(zipFile.GetInputStream(startPartEntry)))
            {
                contents = reader.ReadToEnd();
            }
            XElement contentTypes = XElement.Parse(contents);
            XNamespace xs = contentTypes.GetDefaultNamespace();
            XElement newDefExt = new XElement(xs + "Default", new XAttribute("Extension", "sab"), new XAttribute("ContentType", @"application/binary; modeler=Acis; version=18.0.2application/binary; modeler=Acis; version=18.0.2"));
            contentTypes.Add(newDefExt);
            contentTypes.Save("[Content_Types].xml");
            zipFile.BeginUpdate();
            zipFile.Add("[Content_Types].xml");
            zipFile.CommitUpdate();
            File.Delete("[Content_Types].xml");
            */
            zipFile.BeginUpdate();
            try
            {
                zipFile.Delete("[Content_Types].xml");
                zipFile.CommitUpdate();
            }
            catch{}
        }
    }

그리고 이것을 다음과 같이 사용하십시오 :

foreach (string f in UnitZipList)
{
    AddFileToZip(zipFile, f);
    System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.