2011-01-26 16 views
6

Obecnie pracuję z SharpZipLib pod .NET 2.0 i przez to muszę skompresować pojedynczy plik do jednego skompresowanego archiwum. W tym celu Obecnie używam następujący:SharpZipLib: Kompresowanie pojedynczego pliku do pojedynczego skompresowanego pliku

string tempFilePath = @"C:\Users\Username\AppData\Local\Temp\tmp9AE0.tmp.xml"; 
string archiveFilePath = @"C:\Archive\Archive_[UTC TIMESTAMP].zip"; 

FileInfo inFileInfo = new FileInfo(tempFilePath); 
ICSharpCode.SharpZipLib.Zip.FastZip fZip = new ICSharpCode.SharpZipLib.Zip.FastZip(); 
fZip.CreateZip(archiveFilePath, inFileInfo.Directory.FullName, false, inFileInfo.Name); 

Działa to dokładnie (ish) jak powinien, jednak podczas testów jakie napotkałem niewielki Gotcha. Powiedzmy, że mój katalog temp (czyli katalog zawierający plik wejściowy nieskompresowany) zawiera następujące pliki:

tmp9AE0.tmp.xml //The input file I want to compress 
xxx_tmp9AE0.tmp.xml // Some other file 
yyy_tmp9AE0.tmp.xml // Some other file 
wibble.dat // Some other file 

Kiedy biegnę kompresję wszystkich .xml pliki są zawarte w skompresowanym archiwum. Powodem tego jest ostateczny parametr fileFilter przekazany do metody . Pod maską SharpZipLib przeprowadza dopasowanie do wzorca, a także podnosi pliki z prefiksem xxx_ i yyy_. Zakładam, że to również wykryłoby wszystko, co jest postfiksowane.

Pytanie brzmi: jak skompresować pojedynczy plik za pomocą SharpZipLib? Być może znowu pytanie brzmi: jak mogę sformatować ten fileFilter, aby mecz mógł tylko pobrać plik, który chcę skompresować i nic więcej.

Na marginesie, czy istnieje powód, dla którego System.IO.Compression nie obejmuje klasy ? (Obsługuje tylko GZipStream)

EDIT: Rozwiązanie (pochodzący z przyjętą odpowiedzi od Hans Passant)

Jest to metoda kompresji I wdrożone:

private static void CompressFile(string inputPath, string outputPath) 
{ 
    FileInfo outFileInfo = new FileInfo(outputPath); 
    FileInfo inFileInfo = new FileInfo(inputPath); 

    // Create the output directory if it does not exist 
    if (!Directory.Exists(outFileInfo.Directory.FullName)) 
    { 
     Directory.CreateDirectory(outFileInfo.Directory.FullName); 
    } 

    // Compress 
    using (FileStream fsOut = File.Create(outputPath)) 
    { 
     using (ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipStream = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(fsOut)) 
     { 
      zipStream.SetLevel(3); 

      ICSharpCode.SharpZipLib.Zip.ZipEntry newEntry = new ICSharpCode.SharpZipLib.Zip.ZipEntry(inFileInfo.Name); 
      newEntry.DateTime = DateTime.UtcNow; 
      zipStream.PutNextEntry(newEntry); 

      byte[] buffer = new byte[4096]; 
      using (FileStream streamReader = File.OpenRead(inputPath)) 
      { 
       ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(streamReader, zipStream, buffer); 
      } 

      zipStream.CloseEntry(); 
      zipStream.IsStreamOwner = true; 
      zipStream.Close(); 
     } 
    } 
} 
+2

Co do boku: ZipStream nie miałoby sensu, ponieważ ZIP jest formatem archiwum, w którym można przechowywać więcej niż jeden plik. Przypuszczam, że mogliby zapewnić pełne API do czytania i pisania oraz ZIP-ów, ale oczywiście byłby to o wiele większy wysiłek niż GZipStream. –

+0

Moim zdaniem, kompresując tylko jeden plik, istnieje powód, dla którego nie chcesz używać kompresji GZip, która, jak możesz zauważyć, ma wsparcie w ramach? –

+0

Chciałbym, mógłbym to zrobić z kilkoma liniami kodu. Musi to być zip, ponieważ nasze "wsparcie" nie może obsłużyć złożoności gzip (czy to brzmi sarkastycznie?)). – MrEyes

Odpowiedz

5

Jest to problem, XY, tylko don” t używaj FastZip. Postępuj zgodnie z pierwszym przykładem na this web page, aby uniknąć wypadków.

+0

To działa, jednak skompresowane archiwum zawiera również wszystkie katalogi. Byłoby lepiej, gdyby archiwum zawierało tylko plik na poziomie katalogu głównego i nic więcej. – MrEyes

+1

string entryName = System.IO.Path.GetFileName (nazwa pliku); –

Powiązane problemy