Разархивируйте файлы программно в .net

221

Я пытаюсь распаковать архивированный файл.

Я пытался использовать System.IO.Compression.GZipStreamкласс в .NET, но когда мое приложение работает (на самом деле модульный тест), я получаю это исключение:

System.IO.InvalidDataException: магическое число в заголовке GZip неверно. Убедитесь, что вы передаете поток GZip.

Теперь я понимаю, что .zipфайл не совпадает с .gzфайлом, и это GZipне то же самое, что Zip.

Однако, поскольку я могу извлечь файл, дважды щелкнув вручную сжатый файл и нажав кнопку «Извлечь все файлы», я думаю, что в коде должен быть способ сделать это.

Поэтому я попытался использовать Process.Start()путь к архивному файлу в качестве входных данных. Это заставляет мое приложение открывать окно, показывающее содержимое в заархивированном файле. Это все нормально, но приложение будет установлено на сервере, который не нажимает кнопку «Извлечь все файлы».

Итак, как мне заставить мое приложение извлекать файлы в заархивированных файлах?

Или есть другой способ сделать это? Я предпочитаю делать это в коде, без загрузки каких-либо сторонних библиотек или приложений; отдел безопасности не слишком увлекается этим ...

Петтери
источник
12
Ваш отдел безопасности более счастлив, когда вы пишете собственный код для чего-то, чем пользуетесь библиотекой, которая была отлажена и на которую смотрели, по-видимому, многими глазами? Вы можете использовать библиотеку И «сделать это в коде» (получить исходный код и скомпилировать его самостоятельно), но я считаю, что изобретать колесо - это большая проблема, чем любые проблемы безопасности, вызванные использованием проверенной и проверенной библиотеки.
Джаред Апдайк
10
@Jared - Когда менеджмент получает идею в голову ...
Стивен Эверс
4
Для отдела безопасности меньше риск, если вы приобретаете сторонний продукт. Просто скачайте dotnetzip и переименуйте его в «[введите название компании .ziplibrary.dll»
Simon

Ответы:

59

Мы успешно использовали SharpZipLib во многих проектах. Я знаю, что это сторонний инструмент, но исходный код включен и может дать некоторую информацию, если вы решите изобретать колесо здесь.

Крис Конвей
источник
3
Я пытался использовать SharpZipLib, и он работал нормально. Я думаю, мне придется посмотреть, является ли запрет на сторонние libs и apss строгим правилом или, скорее, правилом.
Петтери
10
Я не знаю о вашей компании, но мой опыт всегда заключался в том, что можно получить исключение из такого рода правил, если вы напишите описание бизнес-случая, почему вы хотите это исключение. Укажите экономию средств против DIY, а также тот факт, что источник может быть изучен. Как запасной вариант, вы часто можете получить разрешение на использование исходного кода, даже если они не позволят вам использовать dll - тогда просто скомпилируйте его самостоятельно (или, по крайней мере, те части, которые вам действительно нужны ...).
RolandTumble
Вам не нужно использовать внешние библиотеки для распаковки zip-файлов, вы можете использовать Shell32 из System32. Пожалуйста, смотрите stackoverflow.com/a/43066281/948694
arturn
490

С .NET 4.5 теперь вы можете разархивировать файлы с помощью .NET Framework:

using System;
using System.IO;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      string startPath = @"c:\example\start";
      string zipPath = @"c:\example\result.zip";
      string extractPath = @"c:\example\extract";

      System.IO.Compression.ZipFile.CreateFromDirectory(startPath, zipPath);
      System.IO.Compression.ZipFile.ExtractToDirectory(zipPath, extractPath);
    }
  }
}

Приведенный выше код был взят непосредственно из документации Microsoft: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFileсодержится в сборке System.IO.Compression.FileSystem. (Спасибо nateirvin ... см. Комментарий ниже)

bsara
источник
118
Кстати, ZipFileсодержится в сборке System.IO.Compression.FileSystem.
nateirvin
73
Это означает, что вам нужно добавить ссылку на DLL в сборку фреймворка System.IO.Compression.FileSystem.dll.
Крис Шиффхауэр
как насчет файлов .rar. Приведенный выше код не может извлечь файлы .rar.
Рагху,
1
Я попытался это сделать в моем основном веб-интерфейсе asp.net, он хорошо читал первую запись, но при второй записи всегда выдает ошибку A local file header is corrupt. Есть хоть что-нибудь по этому поводу?
SoftSan
То же самое с @SoftSan. Я также получил эту ошибку. Что делать?
Богатый
101

Для .Net 4.5+

Не всегда желательно записывать несжатый файл на диск. Как разработчик ASP.Net, мне пришлось бы возиться с разрешениями, чтобы предоставить права моему приложению на запись в файловую систему. Работая с потоками в памяти, я могу обойти все это и читать файлы напрямую:

using (ZipArchive archive = new ZipArchive(postedZipStream))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
         var stream = entry.Open();
         //Do awesome stream stuff!!
    }
}

Кроме того, вы все равно можете записать распакованный файл на диск, вызвав ExtractToFile():

using (ZipArchive archive = ZipFile.OpenRead(pathToZip))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        entry.ExtractToFile(Path.Combine(destination, entry.FullName));
    }
} 

Чтобы использовать ZipArchiveкласс, вам нужно будет добавить ссылку на System.IO.Compressionпространство имен и на System.IO.Compression.FileSystem.

Мистер Эпик
источник
8
Действительно ли требовалось MSFT до 4.5+, чтобы добавить собственный декомпрессор?
Джон Питерс
2
@JohnPeters GZipStream был добавлен в .Net 2.0 ( msdn.microsoft.com/en-us/library/… ). Однако это не облегчало работу с несколькими файлами в архиве в памяти. Новый ZipArchiveобъект отвечает всем требованиям.
Мистер Эпик
1
Это особенно хорошая альтернатива, потому что она позволяет разархивировать без использования файловой системы (в моем случае я работаю со встроенными ресурсами), и это также не стороннее расширение.
ANeves
1
Почему я должен использовать foreachцикл, ExtractToFileкогда я могу просто использовать ZipFile.ExtractToDirectory(inputFile, outputDir);Каково преимущество первого метода?
Пушистый робот
1
в .NET 4.6.1 я не могу получить «ZipArchive» из «System.IO.Compression.FileSystem», любая идея?
Рави Ананд
55

Бесплатно, и никаких внешних файлов DLL. Все в одном файле CS. Одна загрузка - это просто файл CS, другая загрузка - очень простой для понимания пример. Только что попробовал сегодня, и я не могу поверить, насколько простой была установка. Сработало с первой попытки, без ошибок, без ничего.

https://github.com/jaime-olivares/zipstorer

Lukas
источник
Говорил слишком рано! Я хочу мгновенно накачать файлы из потока загрузки http. Это не работает, так как он использует операции поиска в потоке :( Ну, благодаря исходному коду я могу написать свой собственный ZipStream сейчас ...
oyophant
лучшее решение моей проблемы, так как я пишу приложение для обновления, и я не могу вовлекать какие-либо библиотеки DLL в процесс извлечения, с тех пор мне бы пришлось обновить их тоже .... это хорошо. спасибо!
Никлас
27

Используйте библиотеку DotNetZip по адресу http://www.codeplex.com/DotNetZip

библиотека классов и набор инструментов для работы с zip-файлами. Используйте VB, C # или любой другой язык .NET для простого создания, извлечения или обновления zip-файлов ...

DotNetZip работает на ПК с полной версией .NET Framework, а также на мобильных устройствах, использующих .NET Compact Framework. Создавайте и читайте zip-файлы на VB, C # или любом другом языке .NET, или в любой среде сценариев ...

Если все, что вам нужно, это лучший класс DeflateStream или GZipStream для замены класса, встроенного в .NET BCL, у DotNetZip также есть такой. DlateNetZip DeflateStream и GZipStream доступны в виде отдельной сборки на основе порта .NET Zlib. Эти потоки поддерживают уровни сжатия и обеспечивают гораздо лучшую производительность, чем встроенные классы. Существует также ZlibStream для завершения набора (RFC 1950, 1951, 1952) ...

Сэм Акс
источник
1
Хммм ... Но это сторонняя библиотека!
Петтери
30
Как очень наблюдательно с вашей стороны. Если вам не хочется тратить несколько месяцев на внедрение собственного ридера Zip-файлов, это ваш лучший вариант.
Сэм Топор
Это намного лучше, чем SharpZipLib
Kugel
5
Вы задаете мне вопросы об ответе, которому почти 5 лет. Проводить некоторые исследования. Я уверен, что вы найдете ответ.
Сэм Топор
2
@PhilCooper Это очень старый вопрос, я рекомендую использовать встроенный System.IO.Compression.ZipFile. IIRC В прошлом у меня были действительно неудачные опыты с SharpZipLib, основанные на моем опыте создания тысяч молний на лету.
Кугель,
9
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

Чтобы использовать класс ZipFile, необходимо добавить ссылку на сборку System.IO.Compression.FileSystem в вашем проекте.

Махадев Грива
источник
1
Источник: msdn.microsoft.com/en-us/library/...
gkubed
2

Стандартные zip-файлы обычно используют алгоритм deflate.

Для извлечения файлов без использования сторонних библиотек используйте DeflateStream. Вам понадобится немного больше информации о формате архива zip-файла, поскольку Microsoft предоставляет только алгоритм сжатия.

Вы также можете попробовать использовать zipfldr.dll. Это библиотека сжатия Microsoft (сжатые папки из меню «Отправить»). Похоже, это библиотека, но она недокументирована. Вы можете быть в состоянии заставить это работать на Вас через эксперименты.

Кеннет Кокран
источник
Я пробую класс DeflateStream. На этот раз я получаю System.IO.InvalidDataException: длина блока не совпадает с его дополнением ..
Petteri
Как я уже говорил выше, Microsoft предоставила только алгоритм. Вам также понадобится информация о формате zip-архива. ru.wikipedia.org/wiki/ZIP_(file_format) должны помочь вам начать. Смотрите ссылки внизу страницы для ссылок на более подробную информацию.
Кеннет Кохран
2
Я также случайно наткнулся на System.IO.Packaging.Package в .NET 3.5. Похоже, что он может добиться цели, хотя это не очень интуитивно понятно.
Кеннет Кокран
2

Я использую это, чтобы сжать или разархивировать несколько файлов. Regex не требуется, но я использую его для изменения отметки даты и удаления нежелательных подчеркиваний. Я использую пустую строку в строке Compress >> zipPath для добавления префикса ко всем файлам, если это необходимо. Кроме того, я обычно комментирую либо Compress (), либо Decompress () в зависимости от того, что я делаю.

using System;
using System.IO.Compression;
using System.IO;
using System.Text.RegularExpressions;

namespace ZipAndUnzip
{
    class Program
    {
        static void Main(string[] args)
        {
            var directoryPath = new DirectoryInfo(@"C:\your_path\");

            Compress(directoryPath);
            Decompress(directoryPath);
        }

        public static void Compress(DirectoryInfo directoryPath)
        {
            foreach (DirectoryInfo directory in directoryPath.GetDirectories())
            {
                var path = directoryPath.FullName;
                var newArchiveName = Regex.Replace(directory.Name, "[0-9]{8}", "20130913");
                newArchiveName = Regex.Replace(newArchiveName, "[_]+", "_");
                string startPath = path + directory.Name;
                string zipPath = path + "" + newArchiveName + ".zip";

                ZipFile.CreateFromDirectory(startPath, zipPath);
            }

        }

        public static void Decompress(DirectoryInfo directoryPath)
        {
            foreach (FileInfo file in directoryPath.GetFiles())
            {
                var path = directoryPath.FullName;
                string zipPath = path + file.Name;
                string extractPath = Regex.Replace(path + file.Name, ".zip", "");

                ZipFile.ExtractToDirectory(zipPath, extractPath);
            }
        }


    }
}
Филип Хэмби
источник
Для этого требуется точка net 4.5 - просто заметка, как отметили другие, кто ответил с ZipFile, а я все еще использую 3.5.
Thronk
2

Это сделает это System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

Илья Кочетов
источник
1

От сюда :

Сжатые объекты GZipStream, записанные в файл с расширением .gz, могут быть распакованы с использованием многих распространенных инструментов сжатия; однако этот класс по своей природе не обеспечивает функциональность для добавления файлов или извлечения файлов из архивов .zip.

RedWolves
источник
1

Вы можете сделать все это в .NET 3.5, используя DeflateStream. В .NET 3.5 не хватает возможности обрабатывать разделы заголовков файлов, которые используются для организации сжатых файлов. PKWare опубликовал эту информацию, которую вы можете использовать для обработки zip-файла после создания используемых структур. Это не особенно обременительно, и это хорошая практика в создании инструментов без использования стороннего кода.

Это не однострочный ответ, но это вполне выполнимо, если вы хотите и можете не торопиться. Я написал для этого класс за пару часов, и из этого я получил возможность архивировать и распаковывать файлы только с использованием .NET 3.5.

Майкл Блейк
источник
0

Я узнал об этом (пакет Unzip на NuGet) сегодня, так как столкнулся с серьезной ошибкой в ​​DotNetZip и понял, что за последние два года не было так много работы над DotNetZip.

Пакет Unzip скудный, и он сделал свою работу за меня - в нем не было ошибки, которая была в DotNetZip. Кроме того, это был достаточно маленький файл, основанный на Microsoft BCL для фактической распаковки. Я мог легко внести необходимые изменения (чтобы отслеживать прогресс при распаковке). Я рекомендую это.

Пер Лундберг
источник
0

Из Embed Ressources:

using (Stream _pluginZipResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(programName + "." + "filename.zip"))
{
    using (ZipArchive zip = new ZipArchive(_pluginZipResourceStream))
    {
        zip.ExtractToDirectory(Application.StartupPath);
    }
}
Стив Руссо
источник
0

До сих пор я использовал процессы cmd для извлечения файла .iso, копирования его во временный путь с сервера и извлечения на USB-флешку. Недавно я обнаружил, что это прекрасно работает с .iso, которые меньше, чем 10 ГБ. Для iso как 29Gb этот метод как-то застревает.

    public void ExtractArchive()
    {
        try
        {

            try
            {
                Directory.Delete(copyISOLocation.OutputPath, true); 
            }
            catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
            {
            }

            Process cmd = new Process();
            cmd.StartInfo.FileName = "cmd.exe";
            cmd.StartInfo.RedirectStandardInput = true;
            cmd.StartInfo.RedirectStandardOutput = true;
            cmd.StartInfo.CreateNoWindow = true;
            cmd.StartInfo.UseShellExecute = false;
            cmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            //stackoverflow
            cmd.StartInfo.Arguments = "-R";

            cmd.Disposed += (sender, args) => {
                Console.WriteLine("CMD Process disposed");
            };
            cmd.Exited += (sender, args) => {
                Console.WriteLine("CMD Process exited");
            };
            cmd.ErrorDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process error data received");
                Console.WriteLine(args.Data);
            };
            cmd.OutputDataReceived += (sender, args) => {
                Console.WriteLine("CMD Process Output data received");
                Console.WriteLine(args.Data);
            };

            //stackoverflow


            cmd.Start();

            cmd.StandardInput.WriteLine("C:");
            //Console.WriteLine(cmd.StandardOutput.Read());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine("cd C:\\\"Program Files (x86)\"\\7-Zip\\");
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();

            cmd.StandardInput.WriteLine(string.Format("7z.exe x -o{0} {1}", copyISOLocation.OutputPath, copyISOLocation.TempIsoPath));
            //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            cmd.StandardInput.Flush();
            cmd.StandardInput.Close();
            cmd.WaitForExit();
            Console.WriteLine(cmd.StandardOutput.ReadToEnd());
            Console.WriteLine(cmd.StandardError.ReadToEnd());
Разван Балан
источник
0

Вы можете использовать командную строку Info-unzip cod.you нужно всего лишь скачать unzip.exe с официального сайта Info-unzip.

 internal static void Unzip(string sorcefile)
    {
        try
        {
            AFolderFiles.AFolderFilesDelete.DeleteFolder(TempBackupFolder); // delete old folder   
            AFolderFiles.AFolderFilesCreate.CreateIfNotExist(TempBackupFolder); // delete old folder   
           //need to Command command also to export attributes to a excel file
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // window type
            startInfo.FileName = UnzipExe;
            startInfo.Arguments = sorcefile + " -d " + TempBackupFolder;
            process.StartInfo = startInfo;
            process.Start();
            //string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            process.Dispose();
            process.Close();
        }
        catch (Exception ex){ throw ex; }
    }        
Арун Кумар
источник