Jak tworzyć archiwa 7-Zip w .NET?

102

Jak mogę tworzyć archiwa 7-Zip z mojej aplikacji konsoli C #? Muszę mieć możliwość wypakowania archiwów za pomocą zwykłego, szeroko dostępnego programu 7-Zip .


Oto moje wyniki z przykładami podanymi jako odpowiedzi na to pytanie

  • „Wyłuskiwanie” do 7z.exe - to najprostsze i najskuteczniejsze podejście i mogę potwierdzić, że ładnie działa . Jak wspomina workmad3 , muszę tylko zagwarantować, że 7z.exe jest zainstalowany na wszystkich maszynach docelowych, co mogę zagwarantować.
  • 7Zip w kompresji pamięci - dotyczy to kompresji plików cookie „w pamięci” przed wysłaniem do klienta; ta metoda wydaje się nieco obiecująca. Metody opakowujące (opakowanie LZMA SDK ) zwracają typ byte[]. Kiedy piszę byte[]tablicę do pliku, nie mogę jej wyodrębnić za pomocą 7-Zip ( File.7z is not supported archive).
  • 7zSharp Wrapper (znaleziony w CodePlex) - otacza 7z exe / LZMA SDK . Odwołałem się do projektu z mojej aplikacji i pomyślnie utworzyłem kilka plików archiwum, ale nie mogłem wyodrębnić plików za pomocą zwykłego programu 7-Zip ( File.7z is not supported archive).
  • 7Zip SDK aka LZMA SDK - myślę, że nie jestem wystarczająco inteligentny, aby dowiedzieć się, jak tego użyć (dlatego opublikowałem tutaj) ... Wszelkie działające przykłady kodu demonstrujące tworzenie archiwum 7zip, które można wyodrębnić przez zwykły program 7zip?
  • Interfejs CodeProject C # (.NET) dla bibliotek DLL archiwum 7-Zip - obsługuje tylko wyodrębnianie z archiwów 7zip ... Muszę je utworzyć!
  • SharpZipLib - zgodnie z ich FAQ , SharpZipLib nie obsługuje 7zip.
Seibar
źródło
32
Nie pisz tego od Google, gdy wszystkie linki pochodzą z mojego postu poniżej. Niezbyt szanujący dla ludzi poświęciło trochę czasu na szukanie dla Ciebie rozwiązań.
Patrick Desjardins,
3
Wiem, że ten post jest stary, ale w moich badaniach widziałem dziś projekt o nazwie SevenZipSharp. sevenzipsharp.codeplex.com
Timmerz
12
Tylko słowo ostrzeżenia dla przyszłych czytelników. SevenZipSharp wydaje się być porzuconym oprogramowaniem. Na dzień dzisiejszy najnowsza stabilna wersja (0.64) została wydana w sierpniu 2010 z kilkoma nieprzyjemnymi problemami z wielowątkowością (zgodnie z raportami błędów). Od tego czasu opublikowano tylko kilka zatwierdzeń kodu źródłowego .
Anttu

Odpowiedzi:

28

Jeśli możesz zagwarantować, że aplikacja 7-zip zostanie zainstalowana (i w ścieżce) na wszystkich komputerach docelowych, możesz ją odciążyć, wywołując aplikację wiersza poleceń 7z. Nie jest to najbardziej eleganckie rozwiązanie, ale najmniej pracy.

workmad3
źródło
7
W rzeczywistości wysyłamy narzędzie wiersza poleceń 7z z naszymi plikami binarnymi i wysyłamy do niego. U nas działa naprawdę dobrze.
David Mohundro
81

Przykład pliku cookie EggCafe 7Zip To jest przykład (plik cookie kompresujący) z biblioteką DLL 7Zip.

CodePlex Wrapper To jest projekt open source, który wypacza funkcję kompresowania 7z.

7Zip SDK Oficjalny SDK dla 7zip (C, C ++, C #, Java) <--- Moja sugestia

Biblioteka .Net zip firmy SharpDevelop.net

Przykład CodeProject z 7zip

SharpZipLib Wiele zamków błyskawicznych

Patrick Desjardins
źródło
Gotowe i dodałem przydatny projekt open source.
Patrick Desjardins,
1
LOL? Zmień plik cookie za pomocą ciągu znaków ... plik lub cokolwiek ... lol?
Patrick Desjardins,
1
Nie, chcę tylko zobaczyć, czy ktoś wymyślił działający przykład ... Dziękuję za twoje badania, ale żadne z podanych przez ciebie linków nie było w stanie doprowadzić mnie do czegoś, co działa.
Seibar
2
Muszę się zgodzić, że żaden nie ma kodu, który można skopiować i wkleić. SDK to ten, który ma wszystkie odpowiedzi, ale potrzeba trochę czasu i wysiłku, aby coś działało. Rozumiem, że nie chcesz tego robić. Miłego dnia.
Patrick Desjardins,
3
W każdym razie sugeruję usunięcie odniesień SharpDevelop / SharpZipLib, ponieważ oba odnoszą się do tego samego i nie obsługują 7-Zip. Seibar wyraźnie poprosił o 7z. Szukam również rozwiązań 7z, ponieważ ShaprZipLib nie współpracował z archiwum i znalazłem ten wątek. ShaprZipLib to myląca wskazówka!
Onsokumaru
25

SevenZipSharp to kolejne rozwiązanie. Tworzy archiwa 7-zip ...

markhor
źródło
7
Ten post autorstwa markhora faktycznie pochodzi od twórcy projektu SevenZipSharp. SevenZipSharp umożliwia programowy dostęp do biblioteki dll 7Zip, dzięki czemu jest w pełni funkcjonalna. Uważam, że LZMA SDK jest niskopoziomowy i trudny do zrozumienia. Natomiast SevenZipSharp jest dobrze udokumentowany, łatwy w użyciu i ma wiele przykładowych zastosowań w swoim projekcie testowym. Korzystając z przykładów, mogłem szybko kompresować i dekompresować przy użyciu pliku lub pamięci.
John Wigger,
4
Wydaje się, że SevenZipSharp jest opuszczony. Zobacz mój poprzedni komentarz w pytaniu.
Anttu
SevenZipSharp działa wolno. W tej chwili najbardziej zalecanym rozwiązaniem jest użycie Process.Start ("7z.exe ......)
klm_
25

Oto kompletny przykład roboczy przy użyciu zestawu SevenZip SDK w języku C #.

Będzie zapisywać i odczytywać standardowe pliki 7zip utworzone przez aplikację Windows 7zip.

PS. Poprzedni przykład nigdy nie był dekompresowany, ponieważ nigdy nie zapisywał wymaganych informacji o właściwościach na początku pliku.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SevenZip.Compression.LZMA;
using System.IO;
using SevenZip;

namespace VHD_Director
{
    class My7Zip
    {
        public static void CompressFileLZMA(string inFile, string outFile)
        {
            Int32 dictionary = 1 << 23;
            Int32 posStateBits = 2;
            Int32 litContextBits = 3; // for normal files
            // UInt32 litContextBits = 0; // for 32-bit data
            Int32 litPosBits = 0;
            // UInt32 litPosBits = 2; // for 32-bit data
            Int32 algorithm = 2;
            Int32 numFastBytes = 128;

            string mf = "bt4";
            bool eos = true;
            bool stdInMode = false;


            CoderPropID[] propIDs =  {
                CoderPropID.DictionarySize,
                CoderPropID.PosStateBits,
                CoderPropID.LitContextBits,
                CoderPropID.LitPosBits,
                CoderPropID.Algorithm,
                CoderPropID.NumFastBytes,
                CoderPropID.MatchFinder,
                CoderPropID.EndMarker
            };

            object[] properties = {
                (Int32)(dictionary),
                (Int32)(posStateBits),
                (Int32)(litContextBits),
                (Int32)(litPosBits),
                (Int32)(algorithm),
                (Int32)(numFastBytes),
                mf,
                eos
            };

            using (FileStream inStream = new FileStream(inFile, FileMode.Open))
            {
                using (FileStream outStream = new FileStream(outFile, FileMode.Create))
                {
                    SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
                    encoder.SetCoderProperties(propIDs, properties);
                    encoder.WriteCoderProperties(outStream);
                    Int64 fileSize;
                    if (eos || stdInMode)
                        fileSize = -1;
                    else
                        fileSize = inStream.Length;
                    for (int i = 0; i < 8; i++)
                        outStream.WriteByte((Byte)(fileSize >> (8 * i)));
                    encoder.Code(inStream, outStream, -1, -1, null);
                }
            }

        }

        public static void DecompressFileLZMA(string inFile, string outFile)
        {
            using (FileStream input = new FileStream(inFile, FileMode.Open))
            {
                using (FileStream output = new FileStream(outFile, FileMode.Create))
                {
                    SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();

                    byte[] properties = new byte[5];
                    if (input.Read(properties, 0, 5) != 5)
                        throw (new Exception("input .lzma is too short"));
                    decoder.SetDecoderProperties(properties);

                    long outSize = 0;
                    for (int i = 0; i < 8; i++)
                    {
                        int v = input.ReadByte();
                        if (v < 0)
                            throw (new Exception("Can't Read 1"));
                        outSize |= ((long)(byte)v) << (8 * i);
                    }
                    long compressedSize = input.Length - input.Position;

                    decoder.Code(input, output, compressedSize, outSize, null);
                }
            }
        }

        public static void Test()
        {
            CompressFileLZMA("DiscUtils.pdb", "DiscUtils.pdb.7z");
            DecompressFileLZMA("DiscUtils.pdb.7z", "DiscUtils.pdb2");
        }
    }
}
Orwellophile
źródło
15
Zauważ, że jest to czysta kompresja / dekompresja LZMA. Format pliku 7zip to wyższa warstwa, która umożliwia pakowanie wielu plików wraz z nazwami plików / ścieżkami i innymi metadanymi plików.
redcalx
1
@redcalx jest poprawne. Czy ktoś ma pojęcie, jak obrabiać górną warstwę 7zip? Świetnie byłoby nawiązać do innego wpisu SO :)
Christopher J Smith
8

Użyłem sdk.

na przykład:

using SevenZip.Compression.LZMA;
private static void CompressFileLZMA(string inFile, string outFile)
{
   SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();

   using (FileStream input = new FileStream(inFile, FileMode.Open))
   {
      using (FileStream output = new FileStream(outFile, FileMode.Create))
      {
          coder.Code(input, output, -1, -1, null);
          output.Flush();
      }
   }
}
WOPR
źródło
7
A jak rozpakujesz plik? Próbowałem zrobić to samo, używając SevenZip.Compression.LZMA.Decoder i wywołując go za pomocą Code (stream1, stream2, -1, -1, null); To dało wyjątek dotyczący danych w ramach.
Karsten
3
 string zipfile = @"E:\Folderx\NPPES.zip";
 string folder = @"E:\TargetFolderx";

 ExtractFile(zipfile,folder);
public void ExtractFile(string source, string destination)
        {
            // If the directory doesn't exist, create it.
            if (!Directory.Exists(destination))
                Directory.CreateDirectory(destination);

            //string zPath = ConfigurationManager.AppSettings["FileExtactorEXE"];
          //  string zPath = Properties.Settings.Default.FileExtactorEXE; ;

            string zPath=@"C:\Program Files\7-Zip\7zG.exe";

            try
            {
                ProcessStartInfo pro = new ProcessStartInfo();
                pro.WindowStyle = ProcessWindowStyle.Hidden;
                pro.FileName = zPath;
                pro.Arguments = "x \"" + source + "\" -o" + destination;
                Process x = Process.Start(pro);
                x.WaitForExit();
            }
            catch (System.Exception Ex) { }
        }

Wystarczy zainstalować 7 zip ze źródła i przekazać parametr do metody.

Dzięki. Proszę polub odpowiedź.

Vishal Sen
źródło
To zadziałało dla mnie w usłudze Windows z 7za.exe
Marco Duindam
1

Używam tego kodu

                string PZipPath = @"C:\Program Files\7-Zip\7z.exe";
                string sourceCompressDir = @"C:\Test";
                string targetCompressName = @"C:\Test\abc.zip";
                string CompressName = targetCompressName.Split('\\').Last();
                string[] fileCompressList = Directory.GetFiles(sourceCompressDir, "*.*");

                    if (fileCompressList.Length == 0)
                    {
                        MessageBox.Show("No file in directory", "Important Message");
                        return;
                    }
                    string filetozip = null;
                    foreach (string filename in fileCompressList)
                    {
                        filetozip = filetozip + "\"" + filename + " ";
                    }

                    ProcessStartInfo pCompress = new ProcessStartInfo();
                    pCompress.FileName = PZipPath;
                    if (chkRequestPWD.Checked == true)
                    {
                        pCompress.Arguments = "a -tzip \"" + targetCompressName + "\" " + filetozip + " -mx=9" + " -p" + tbPassword.Text;
                    }
                    else
                    {
                        pCompress.Arguments = "a -tzip \"" + targetCompressName + "\" \"" + filetozip + "\" -mx=9";
                    }
                    pCompress.WindowStyle = ProcessWindowStyle.Hidden;
                    Process x = Process.Start(pCompress);
                    x.WaitForExit();
lifestylebyatom
źródło
1

Zainstaluj pakiet NuGet o nazwie SevenZipSharp.Interop

Następnie:

SevenZipBase.SetLibraryPath(@".\x86\7z.dll");
var compressor = new SevenZip.SevenZipCompressor();
var filesToCompress = Directory.GetFiles(@"D:\data\");
compressor.CompressFiles(@"C:\archive\abc.7z", filesToCompress);
Fidel
źródło
Próbowałem dodać plik do istniejącego archiwum 7z za jego pomocą i otrzymałem uszkodzone archiwum.
Geograph
1

Kilka dodatkowych informacji testowych na temat kodu @Orwellophile przy użyciu pliku tekstowego 17,9 MB.
Używanie wartości właściwości w przykładowym kodzie „tak jak jest” będzie miało OGROMNY negatywny wpływ na wydajność, zajmuje to 14,16 sekundy .

Ustawienie właściwości na następujące wykonaj to samo zadanie w 3,91 sekundy (np. Archiwum będzie miało te same informacje o kontenerze, czyli: możesz rozpakować i przetestować archiwum za pomocą 7zip, ale nie ma informacji o nazwie pliku)

Natywny 7zip 2 sek.

CoderPropID[] propIDs =  {
  //CoderPropID.DictionarySize,
  //CoderPropID.PosStateBits,
  //CoderPropID.LitContextBits,
  //CoderPropID.LitPosBits,
  //CoderPropID.Algorithm,
  //CoderPropID.NumFastBytes,
  //CoderPropID.MatchFinder,
  CoderPropID.EndMarker
};
object[] properties = {
  //(Int32)(dictionary),
  //(Int32)(posStateBits),
  //(Int32)(litContextBits),
  //(Int32)(litPosBits),
  //(Int32)(algorithm),
  //(Int32)(numFastBytes),
  //mf,
  eos
};

Zrobiłem kolejny test przy użyciu natywnego 7zip i 1,2 GB pliku kopii zapasowej SQL (.bak)
7zip (maksymalna kompresja): 1 minuta
LZMA SDK (@Orwellophile z powyższym ustawieniem właściwości): 12:26 min :-(
Plik wyjściowy mniej więcej ten sam rozmiar .

Myślę więc, że sam użyję rozwiązania opartego na silniku c / c ++, np. Albo wywołam plik wykonywalny 7zip z c #, albo użyję squid-box / SevenZipSharp , który jest opakowaniem wokół pliku dll 7zip c / c ++ i wydaje się być najnowszym widelcem SevenZipSharp. Nie testowałem opakowania, ale mam nadzieję, że działa tak samo, jak natywny 7zip. Ale miejmy nadzieję, że da to możliwość kompresji strumienia, czego oczywiście nie możesz, jeśli zadzwonisz bezpośrednio do exe. W przeciwnym razie myślę, że nie ma żadnej przewagi nad wywołaniem exe. Opakowanie ma kilka dodatkowych zależności, więc nie spowoduje, że opublikowany projekt będzie „czystszy”.

Swoją drogą wydaje się, że zespół .Net Core rozważa zaimplementowanie LZMA w klasie system.io w .Core ver. 5, byłoby świetnie!

(Wiem, że to rodzaj komentarza, a nie odpowiedzi, ale aby móc podać fragment kodu, nie może to być komentarz)

MrCalvin
źródło
0

Najłatwiejszym sposobem jest praca z plikami .zip zamiast .7z i użycie Dot Net Zip

Podczas wyłączania poleceń 7zip do powłoki występują inne problemy, takie jak uprawnienia użytkownika, miałem problem z SevenZipSharp.

Private Function CompressFile(filename As String) As Boolean
Using zip As New ZipFile()
    zip.AddFile(filename & ".txt", "")
    zip.Save(filename & ".zip")
End Using

Return File.Exists(filename & ".zip")
End Function
Brent
źródło
0

SharpCompress to moim zdaniem jedna z najmądrzejszych bibliotek kompresji. Obsługuje LZMA (7-zip), jest łatwy w użyciu i aktywnie rozwijany.

Ponieważ ma już obsługę przesyłania strumieniowego LZMA, w momencie pisania tego tekstu obsługuje niestety tylko odczyt archiwów 7-zip. ALE zapis archiwalny jest na ich liście zadań do wykonania (zobacz plik readme). Dla przyszłych czytelników: sprawdź, czy aktualny status jest dostępny tutaj: https://github.com/adamhathcock/sharpcompress/blob/master/FORMATS.md

Mario Eis
źródło