Создать нормальный почтовый файл программно - PullRequest
35 голосов
/ 16 марта 2010

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

Спасибо

Ответы [ 11 ]

61 голосов
/ 27 октября 2013

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

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

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

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

27 голосов
/ 31 марта 2014

Теперь вы можете использовать класс 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);
            }
        }
    }
}
20 голосов
/ 11 февраля 2015

Мои 2 цента:

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

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

20 голосов
/ 16 марта 2010

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

Архивируйте ваши потоки с System.IO.Packaging

Я рекомендую использовать system.io.packacking. Это подавляет ваши зависимости (только структура). Пост Jgalloway (первая ссылка) представляет собой хороший пример добавления двух файлов в zip-файл. Да, это более многословно, но вы можете легко создать фасад (в некоторой степени это делает его AddFileToZip).

НТН

17 голосов
/ 16 марта 2010

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

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

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

Сжатие Zip-файлов с помощью Windows Shell API и C

enter image description here

Введение

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

Фон

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

Использование кода

В следующем коде показано, как использовать Windows Shell API для сжатия файла Zip. Сначала вы создаете пустой Zip-файл. Для этого создайте правильно сконструированный байтовый массив, а затем сохраните этот массив в виде файла с расширением .zip. Как я узнал, какие байты поместить в массив? Ну, я просто использовал Windows, чтобы создать файл Zip с одним сжатым файлом внутри. Затем я открыл Zip с Windows и удалил сжатый файл. Это оставило меня с пустым почтовым индексом. Затем я открыл пустой 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");
}
6 голосов
/ 16 марта 2010

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

4 голосов
/ 16 марта 2010

Вы должны посмотреть на Пакеты Zip

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

4 голосов
/ 16 марта 2010

.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());
                    }
                }
            }
        }
2 голосов
/ 30 марта 2017

Это можно сделать, добавив ссылку на 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 в MSDN

1 голос
/ 08 сентября 2017

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

Этот код принимает список путей к файлам и создает из них 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.");
        }
    }
}
...