Подтвердить что ты не робот

Создавать нормальный zip файл программно

Я видел много учебников о том, как сжать один файл в С#. Но я должен иметь возможность создать обычный *.zip файл из более чем одного файла. Есть ли что-нибудь в .NET, которое может это сделать? Что бы вы предложили (имея в виду, что я под строгими правилами и не могу использовать другие библиотеки)

Спасибо

4b9b3361

Ответ 1

Изменить: если вы используете .Net 4.5 или новее, это встроенный в инфраструктуру

Для более ранних версий или для большего контроля вы можете использовать функции оболочки Windows, как описано здесь, в CodeProject от Gerald Gibson Jr.

Я скопировал текст статьи ниже, как написано (оригинальная лицензия: общедоступный домен)

Сжать Zip файлы с помощью API оболочки Windows и C

введите описание изображения здесь

Введение

Это следующая статья к тому, что я написал о распаковке Zip файлов. С помощью этого кода вы можете использовать API-интерфейс Windows Shell в С# для сжатия Zip файлов и сделать это, не показывая окно "Копировать прогресс", показанное выше. Обычно, когда вы используете API-интерфейс Shell для сжатия Zip файла, он отображает окно "Копирование прогресса", даже если вы зададите параметры, чтобы сообщить Windows, чтобы они не отображались. Чтобы обойти это, вы переместите код Shell API в отдельный исполняемый файл, а затем запустите этот исполняемый файл, используя класс .NET Process, чтобы установить стиль окна процесса в "Скрытый".

Фон

Вам всегда нужно было сжимать Zip файлы и требовать лучшего Zip, чем то, что поставляется со многими бесплатными библиотеками сжатия там? То есть вам необходимо сжать папки и подпапки, а также файлы. Windows Zipping может сжимать больше, чем отдельные файлы. Все, что вам нужно, - это способ программно заставить Windows беззвучно сжимать эти Zip файлы. Конечно, вы могли бы потратить 300 долларов на один из коммерческих компонентов Zip, но его сложно обыграть, если вам нужно только сжать иерархии папок.

Используя код

В следующем коде показано, как использовать Windows Shell API для сжатия Zip файла. Сначала вы создаете пустой Zip файл. Для этого создайте правильно построенный массив байтов, а затем сохраните этот массив как файл с расширением ".zip". Как я узнал, какие байты помещать в массив? Ну, я просто использовал Windows для создания Zip файла с одним сжатым внутри. Затем я открыл Zip с Windows и удалил сжатый файл. Это оставило меня с пустым Zip. Затем я открыл пустой Zip файл в шестнадцатеричном редакторе (Visual Studio) и просмотрел значения шестнадцатеричного байта и преобразовал их в десятичный с помощью Windows Calc и скопировал эти десятичные значения в мой массив байтов. Исходная папка указывает на папку, которую вы хотите сжать. Целевая папка указывает на пустой файл Zip, который вы только что создали. Этот код как есть сжимает Zip файл, однако он также покажет окно "Копирование прогресса". Чтобы этот код работал, вам также необходимо установить ссылку на библиотеку COM. В окне "Ссылки" перейдите на вкладку "COM" и выберите библиотеку с надписью "Microsoft Shell Controls and Automation".

//Create an empty zip file
byte[] emptyzip = 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};

FileStream fs = File.Create(args[1]);
fs.Write(emptyzip, 0, emptyzip.Length);
fs.Flush();
fs.Close();
fs = null;

//Copy a folder and its contents into the newly created zip file
Shell32.ShellClass sc = new Shell32.ShellClass();
Shell32.Folder SrcFlder = sc.NameSpace(args[0]);
Shell32.Folder DestFlder = sc.NameSpace(args[1]); 
Shell32.FolderItems items = SrcFlder.Items();
DestFlder.CopyHere(items, 20);

//Ziping a file using the Windows Shell API 
//creates another thread where the zipping is executed.
//This means that it is possible that this console app 
//would end before the zipping thread 
//starts to execute which would cause the zip to never 
//occur and you will end up with just
//an empty zip file. So wait a second and give 
//the zipping thread time to get started
System.Threading.Thread.Sleep(1000);

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

В приведенном ниже коде показан обработчик события нажатия кнопки, содержащий код, используемый для запуска консольного приложения, так что во время сжатия отсутствует пользовательский интерфейс:

private void btnUnzip_Click(object sender, System.EventArgs e)
{
    //Test to see if the user entered a zip file name
    if(txtZipFileName.Text.Trim() == "")
    {
        MessageBox.Show("You must enter what" + 
               " you want the name of the zip file to be");
        //Change the background color to cue the user to what needs fixed
        txtZipFileName.BackColor = Color.Yellow;
        return;
    }
    else
    {
        //Reset the background color
        txtZipFileName.BackColor = Color.White;
    }

    //Launch the zip.exe console app to do the actual zipping
    System.Diagnostics.ProcessStartInfo i =
        new System.Diagnostics.ProcessStartInfo(
        AppDomain.CurrentDomain.BaseDirectory + "zip.exe");
    i.CreateNoWindow = true;
    string args = "";


    if(txtSource.Text.IndexOf(" ") != -1)
    {
        //we got a space in the path so wrap it in double qoutes
        args += "\"" + txtSource.Text + "\"";
    }
    else
    {
        args += txtSource.Text;
    }

    string dest = txtDestination.Text;

    if(dest.EndsWith(@"\") == false)
    {
        dest += @"\";
    }

    //Make sure the zip file name ends with a zip extension
    if(txtZipFileName.Text.ToUpper().EndsWith(".ZIP") == false)
    {
        txtZipFileName.Text += ".zip";
    }

    dest += txtZipFileName.Text;

    if(dest.IndexOf(" ") != -1)
    {
        //we got a space in the path so wrap it in double qoutes
        args += " " + "\"" + dest + "\"";
    }
    else
    {
        args += " " + dest;
    }

    i.Arguments = args;


    //Mark the process window as hidden so 
    //that the progress copy window doesn't show
    i.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;    
    System.Diagnostics.Process p = System.Diagnostics.Process.Start(i);
    p.WaitForExit();
    MessageBox.Show("Complete");
}

Ответ 2

Просто обновите это для всех, кто наткнулся на этот вопрос.

Начиная с .NET 4.5 вы можете сжать каталог с помощью System.IO.Compression в zip файл. Вы должны добавить System.IO.Compression.FileSystem в качестве ссылки, поскольку по умолчанию не ссылаются. Затем вы можете написать:

System.IO.Compression.ZipFile.CreateFromDirectory(dirPath, zipFile);

Единственная потенциальная проблема заключается в том, что эта сборка недоступна для приложений Windows Store.

Ответ 3

Теперь вы можете использовать класс ZipArchive (System.IO.Compression.ZipArchive), доступный из.NET 4.5

Пример: создание zip файлов PDF

using (var fileStream = new FileStream(@"C:\temp\temp.zip", FileMode.CreateNew))
{
    using (var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true))
    {
        foreach (var creditNumber in creditNumbers)
        {
            var pdfBytes = GeneratePdf(creditNumber);
            var fileName = "credit_" + creditNumber + ".pdf";
            var zipArchiveEntry = archive.CreateEntry(fileName, CompressionLevel.Fastest);
            using (var zipStream = zipArchiveEntry.Open())
                zipStream.Write(pdfBytes, 0, pdfBytes.Length);
            }
        }
    }
}

Ответ 4

Вот несколько ресурсов, которые вы могли бы подумать: Создание Zip-архивов в .NET(без внешней библиотеки, такой как SharpZipLib)

Почтовый поток с помощью System.IO.Packaging

Мои рекомендации и предпочтения будут заключаться в использовании system.io.packacking. Это снижает ваши зависимости (только рамки). Сообщение Jgalloways (первая ссылка) является хорошим примером добавления двух файлов в zip файл. Да, это более многословно, но вы можете легко создать фасад (в той степени, в какой его делает AddFileToZip).

НТН

Ответ 5

Мои 2 цента:

    using (ZipArchive archive = ZipFile.Open(zFile, ZipArchiveMode.Create))
    {
        foreach (var fPath in filePaths)
        {
            archive.CreateEntryFromFile(fPath,Path.GetFileName(fPath));
        }
    }

Таким образом, файлы Zip могут быть созданы непосредственно из файлов/dirs.

Ответ 6

Вы можете попробовать SharpZipLib. Является открытым исходным кодом, независимым от платформы чистым кодом С#.

Ответ 7

Вы должны изучить Почтовые пакеты

Они представляют собой более структурированную версию обычных ZIP-архивов, требующих некоторых метафайлов в корне. Таким образом, другие инструменты ZIP могут открывать пакет, но API Sysytem.IO.Packaging не может открыть все ZIP файлы.

Ответ 8

У .NET есть встроенная функция сжатия файлов в System.IO.Compression пространстве имен. Используя это, вам не нужно брать дополнительную библиотеку в качестве зависимости. Эта функциональность доступна в .NET 2.0.

Вот как сделать сжатие со страницы MSDN, с которой я связан:

    public static void Compress(FileInfo fi)
    {
        // Get the stream of the source file.
        using (FileStream inFile = fi.OpenRead())
        {
            // Prevent compressing hidden and already compressed files.
            if ((File.GetAttributes(fi.FullName) & FileAttributes.Hidden)
                    != FileAttributes.Hidden & fi.Extension != ".gz")
            {
                // Create the compressed file.
                using (FileStream outFile = File.Create(fi.FullName + ".gz"))
                {
                    using (GZipStream Compress = new GZipStream(outFile,
                            CompressionMode.Compress))
                    {
                        // Copy the source file into the compression stream.
                        byte[] buffer = new byte[4096];
                        int numRead;
                        while ((numRead = inFile.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            Compress.Write(buffer, 0, numRead);
                        }
                        Console.WriteLine("Compressed {0} from {1} to {2} bytes.",
                            fi.Name, fi.Length.ToString(), outFile.Length.ToString());
                    }
                }
            }
        }

Ответ 9

Это можно сделать только с одной строкой кода, используя только Dot Net. Ниже приведен пример кода, скопированного из MSDN

Шаг 1: добавьте ссылку на System.IO.Compression.FileSystem

Шаг 2: Следуйте приведенному ниже коде

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

            ZipFile.CreateFromDirectory(startPath, zipPath);

            ZipFile.ExtractToDirectory(zipPath, extractPath);
        }

Ответ 10

Это можно сделать, добавив ссылку на System.IO.Compression и System.IO.Compression.Filesystem.

Пример метода createZipFile() может выглядеть следующим образом:

public static void createZipFile(string inputfile, string outputfile, CompressionLevel compressionlevel)
        {
            try
            {
                using (ZipArchive za = ZipFile.Open(outputfile, ZipArchiveMode.Update))
                {
                    //using the same file name as entry name
                    za.CreateEntryFromFile(inputfile, inputfile);
                }
            }
            catch (ArgumentException)
            {
                Console.WriteLine("Invalid input/output file.");
                Environment.Exit(-1);
            }
}

, где

  • inputfile = строка с именем файла для сжатия (для этого например, вы должны добавить расширение)
  • outputfile = строка с именем zip файла назначения

Подробнее о ZipFile Class в MSDN

Ответ 11

Вот код, который я написал после использования вышеуказанных сообщений. Спасибо за вашу помощь.

Этот код принимает список путей к файлу и создает из них zip файл.

public class Zip
{
    private string _filePath;
    public string FilePath { get { return _filePath; } }

    /// <summary>
    /// Zips a set of files
    /// </summary>
    /// <param name="filesToZip">A list of filepaths</param>
    /// <param name="sZipFileName">The file name of the new zip (do not include the file extension, nor the full path - just the name)</param>
    /// <param name="deleteExistingZip">Whether you want to delete the existing zip file</param>
    /// <remarks>
    /// Limitation - all files must be in the same location. 
    /// Limitation - must have read/write/edit access to folder where first file is located.
    /// Will throw exception if the zip file already exists and you do not specify deleteExistingZip
    /// </remarks>
    public Zip(List<string> filesToZip, string sZipFileName, bool deleteExistingZip = true)
    {
        if (filesToZip.Count > 0)
        {
            if (File.Exists(filesToZip[0]))
            {

                // Get the first file in the list so we can get the root directory
                string strRootDirectory = Path.GetDirectoryName(filesToZip[0]);

                // Set up a temporary directory to save the files to (that we will eventually zip up)
                DirectoryInfo dirTemp = Directory.CreateDirectory(strRootDirectory + "/" + DateTime.Now.ToString("yyyyMMddhhmmss"));

                // Copy all files to the temporary directory
                foreach (string strFilePath in filesToZip)
                {
                    if (!File.Exists(strFilePath))
                    {
                        throw new Exception(string.Format("File {0} does not exist", strFilePath));
                    }
                    string strDestinationFilePath = Path.Combine(dirTemp.FullName, Path.GetFileName(strFilePath));
                    File.Copy(strFilePath, strDestinationFilePath);
                }

                // Create the zip file using the temporary directory
                if (!sZipFileName.EndsWith(".zip")) { sZipFileName += ".zip"; }
                string strZipPath = Path.Combine(strRootDirectory, sZipFileName);
                if (deleteExistingZip == true && File.Exists(strZipPath)) { File.Delete(strZipPath); }
                ZipFile.CreateFromDirectory(dirTemp.FullName, strZipPath, CompressionLevel.Fastest, false);

                // Delete the temporary directory
                dirTemp.Delete(true);

                _filePath = strZipPath;                    
            }
            else
            {
                throw new Exception(string.Format("File {0} does not exist", filesToZip[0]));
            }
        }
        else
        {
            throw new Exception("You must specify at least one file to zip.");
        }
    }
}