Как заархивировать файл на C # без сторонних API?

Я почти уверен, что это не дубликат, так что потерпите меня минутку.

Как я могу программно (C #) архивировать файл (в Windows) без использования сторонних библиотек? Мне нужен собственный вызов Windows или что-то в этом роде; Мне действительно не нравится идея начинать процесс, но я буду, если это будет абсолютно необходимо. Звонок в Пиновке был бы намного лучше.

Если это не удается, позвольте мне сказать вам, чего я действительно пытаюсь достичь: мне нужна возможность разрешить пользователю загружать набор документов за один запрос. Есть идеи, как этого добиться?


person Esteban Araya    schedule 02.06.2009    source источник
comment
comment
@Chesso: Да, со страницы ASPX.   -  person Esteban Araya    schedule 02.06.2009
comment
Я нашел этот пример полезным, когда несколько недель назад искал то же самое: syntaxwarriors.com/2012/   -  person JensB    schedule 23.09.2012
comment
При использовании 4.5 Framework теперь есть классы ZipArchive и ZipFile.   -  person GalacticJello    schedule 25.11.2013
comment
Кто-нибудь использовал DotNetZip ??   -  person Hot Licks    schedule 20.08.2014
comment
Чистый класс C # для хранения файлов в формате Zip (под лицензией MIT)   -  person user423430    schedule 08.06.2016


Ответы (7)


Вы используете .NET 3.5? Вы можете использовать ZipPackage и родственные классы. Это больше, чем просто архивирование списка файлов, потому что ему нужен MIME-тип для каждого добавляемого файла. Он может делать то, что вы хотите.

В настоящее время я использую эти классы для решения аналогичной проблемы, чтобы заархивировать несколько связанных файлов в один файл для загрузки. Мы используем расширение файла, чтобы связать загружаемый файл с нашим настольным приложением. Одна небольшая проблема, с которой мы столкнулись, заключалась в том, что невозможно просто использовать сторонний инструмент, такой как 7-zip, для создания zip-файлов, потому что код на стороне клиента не может его открыть - ZipPackage добавляет скрытый файл, описывающий тип содержимого каждый компонентный файл и не может открыть ZIP-файл, если этот файл типа содержимого отсутствует.

person Brian Ensink    schedule 02.06.2009
comment
О, ТАК, как я тебя люблю! Спасибо, Брайан; Юо только что избавил нас от многих головных болей и немного $ $ $. - person Esteban Araya; 02.06.2009
comment
Обратите внимание, что это не всегда работает наоборот. Некоторые Zip-файлы не будут регидратироваться с использованием класса ZipPackage. Файлы, созданные с помощью ZipPackage, будут такими, чтобы у вас все было хорошо. - person Craig; 02.06.2009
comment
Обратите внимание, что ZipPackage не может добавляться к существующему заархивированному пакету. - person ΩmegaMan; 23.10.2013
comment
Вздох: Тип или пространство имен Packaging не существует в пространстве имен System.IO. - person Hot Licks; 20.08.2014
comment
(Ответ на вздох выше: откройте ссылки и добавьте (что довольно нелогично) WindowsBase.) - person Hot Licks; 20.08.2014

Как я могу программно (C #) архивировать файл (в Windows) без использования сторонних библиотек?

При использовании 4.5+ Framework теперь есть ZipArchive и ZipFile.

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

Для .NET Core, нацеленного на net46, вам необходимо добавить зависимости для

  • 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;
person GalacticJello    schedule 25.11.2013
comment
Как это не получило больше голосов? Это единственный прямой ответ. - person Matt Cashatt; 08.01.2014
comment
Потому что этому вопросу пять лет, а этому ответу всего два месяца. Дерп :-P - person Riegardt Steyn; 15.01.2014
comment
@heliac по-прежнему Stackoverflow штука должна быть репозиторием вопросов и ответов, и в духе лучший ответ должен быть наверху ... (черт, я знал, что это не сработает) - person Offler; 18.02.2014
comment
На всякий случай, если это кому-то поможет, второй аргумент - это запись в файл. Это путь, по которому будет извлечен файл, относительно распакованной папки. В Windows 7 я обнаружил, что если запись файла представляет собой полный путь, например, @D: \ Temp \ file1.pdf, собственный экстрактор Windows не работает. Вы можете столкнуться с этой проблемой, если просто используете имена файлов, полученные из Directory.GetFiles (). Лучше всего извлекать имя файла, используя Path.GetFileName () в качестве аргумента записи файла. - person Manish; 12.08.2014
comment
Кажется, я не могу найти это в 4.5.2? - person user3791372; 02.05.2016
comment
@ user3791372, вам нужно явно добавить ссылку на system.io.compression. просто иметь систему не сработает. - person RayLoveless; 10.08.2016
comment
Также помните, что ZipFile.CreateFromDirectory(filesDirectory, zipFileName) можно использовать для заархивирования всего каталога - person Savage; 11.09.2019

Я был в той же ситуации, желая использовать .NET вместо сторонней библиотеки. Как уже упоминалось выше, простого использования класса ZipPackage (представленного в .NET 3.5) недостаточно. Есть дополнительный файл, который ДОЛЖЕН быть включен в архив, чтобы ZipPackage работал. Если добавить этот файл, то полученный ZIP-пакет можно будет открыть прямо из проводника Windows - без проблем.

Все, что вам нужно сделать, это добавить файл [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>

И C # для создания ZIP-файла:

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)); 
            } 
        } 
    } 

Примечание:

person Joshua    schedule 01.06.2012
comment
Хороший образец, но он не создает ZIP-файл. Распаковывает существующий файл. - person Matt Varblow; 27.06.2012

На основе ответа Саймона Маккензи на этот вопрос, я бы предложил использовать пару таких методов:

    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);
    }
}
person mccdyl001    schedule 08.10.2014


Добавьте в свой проект эти 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);
person Teemo    schedule 22.01.2019

person    schedule
comment
Как я могу получить sourceFileName, когда я нахожусь внутри webapi и получаю HttpContext.Current.Request? - person Olivertech; 29.12.2018
comment
Сжать еще один файл? - person Kiquenet; 20.03.2019