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


221

Я намагаюся програматично розпакувати файл, який зберігається в папері.

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

System.IO.InvalidDataException: Магічне число в заголовку GZip невірно. Переконайтеся, що ви проїжджаєте в потоці GZip ..

Тепер я розумію, що .zipфайл - це не те саме, що .gzфайл, і GZipце не те саме , що файл Zip.

Однак, оскільки я в змозі витягнути файл, вручну двічі клацнувши заархівований файл, а потім натиснувши кнопку "Витягнути всі файли", я думаю, що в коді має бути спосіб зробити це.

Тому я спробував використовувати Process.Start()з вкладкою шлях до zipped-файлу. Це призводить до того, що мій додаток відкриває Вікно, де відображається вміст у заархівованому файлі. Це все добре, але додаток буде встановлено на сервер, у якому ніхто не буде натиснути кнопку "Витягнути всі файли".

Отже, як я можу отримати свою програму для витягування файлів у заархівованих файлах?

Або є інший спосіб це зробити? Я вважаю за краще це робити в коді, не завантажуючи сторонніх бібліотек чи програм; відділ безпеки не надто фантазує з цього приводу ...


12
Ваш відділ безпеки щасливіший, коли ви щось пишете власним кодом, ніж користуєтеся бібліотекою, яку налагодили та переглянули, мабуть, багатьма очима? Ви можете використовувати бібліотеку ТА "зробити це в коді" (дістаньте джерело та складіть його самостійно), але я вважаю, що винахід колеса є більшою проблемою, ніж будь-які проблеми із безпекою, викликані використанням перевіреної та справжньої бібліотеки.
Джаред Updike

10
@Jred - Коли керівництво отримує ідею в їх голові ...
Стівен Еверс

4
Для відділу безпеки існує менший ризик, якщо ви отримаєте сторонній продукт. Просто завантажте dotnetzip та перейменуйте його "[вставте назву компанії] .ziplibrary.dll"
Саймон

Відповіді:


59

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


3
Я спробував використовувати SharpZipLib, і це спрацювало чудово. Напевно, мені доведеться перевірити, чи заборона проти сторонніх ліб та апсс є суворим правилом чи більше керівним принципом.
Петтері

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 ... дивіться коментар нижче)


118
BTW, ZipFileміститься в складі System.IO.Compression.FileSystem.
nateirvin

73
Що означає, що вам потрібно додати посилання DLL до складання рамки System.IO.Compression.FileSystem.dll.
Кріс Шиффхауер

як щодо файлів .rar вище код не вдається вилучити файли .rar
Рагу

1
Я спробував це в моєму веб-api 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


Говорити занадто рано! Хочу миттєво надути файли з потоку завантаження http. Це не працює, оскільки він використовує операції Seek у потоці :( Ну, завдяки вихідному коду я можу зараз написати свій власний ZipStream ...
oyophant

найкраще рішення моєї проблеми, оскільки я писав додаток для оновлення, і я не можу залучати будь-які DLL до процесу вилучення з тих пір, мені доведеться теж оновити їх .... це добре. Дякую!
Ніклас

27

Використовуйте бібліотеку DotNetZip за адресою http://www.codeplex.com/DotNetZip

бібліотека класів та набір інструментів для обробки zip-файлів. Використовуйте VB, C # або будь-яку мову .NET, щоб легко створювати, витягувати або оновлювати поштові файли ...

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

Якщо все, що вам потрібно, - кращий клас DeflateStream або GZipStream, який замінить той, який вбудований у .NET BCL, і DotNetZip також має це. DeflateStream та GZipStream DotNetZip доступні в окремій збірці на основі .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 у вашому проекті



2

Стандартні ZIP-файли зазвичай використовують алгоритм дефляції.

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

Ви також можете спробувати використовувати zipfldr.dll. Це бібліотека стиснення Microsoft (стислі папки з меню "Надіслати в"). Здається, це бібліотека com, але вона недокументована. Можливо, ви зможете змусити його працювати за допомогою експериментів.


Я пробую клас DeflateStream. Цього разу я отримую System.IO.InvalidDataException: Довжина блоку не відповідає його доповненню ..
Petteri

Як я вже говорив вище, Microsoft лише надала алгоритм. Вам також знадобиться інформація про формат zip-архіву. en.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


1

Від сюди :

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


1

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

Це не одна відповідь, але це цілком можливо, якщо ви готові та вмієте витратити час самостійно. Я написав клас, щоб це зробити за пару годин, і те, що я отримав, - це можливість копіювати та розпаковувати файли лише за допомогою .NET 3.5.


0

Я дізнався про це (пакунок Unzip на NuGet) сьогодні, оскільки я наткнувся на важку помилку в DotNetZip, і зрозумів, що за DotNetZip протягом останніх двох років не було так багато роботи.

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


0

З вбудованих ресурсів:

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 Гбіт. Для ізо як 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.потрібно лише завантажити 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; }
    }        
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.