Kompresja pliku w pamięci.

0

Witam
Chce dokonać kompresji pliku w pamięci, męczę się już tym sporo czasu i nie mogę znaleźć rozwiązania. Zależy mi aby rozwiązanie opierało się na standardowej bibliotece oraz aby wszystko działo się pamięci. Plik zostanie później zwrócony w kontrolerze do ściągnięcia. Do tej pory chciałem to uzyskać w taki sposób:

  1. Generowanie Xml z obiektu do MemoryStream
  2. Teraz chciał bym tego xml skompresować tak aby po rozpakowaniu pliku np. za pomocą 7-Zip uzyskać plik xml.
1

Spróbuj tego stackoverflow.com/questions/7343465/compression-decompression-string-with-c-sharp

Kiedyś wygrzebałem kompresję w pamięci w Pythonie, ale użycie innego języka pewnie Cię nie interesuje...

2

Jeśli chodzi o standardowe rozwiązania, to są klasy: DeflateStream i GZipStream, a w .NET 4.5 doszła jeszcze ZipArchive.

1
  1. Teraz chciał bym tego xml skompresować tak aby po rozpakowaniu pliku np. za pomocą 7-Zip uzyskać plik xml.

Używając GZipStream pamiętaj, żeby wynikowemu plikowi nadać rozszerzenie .gz. Nie jest to archiwum ZIP i inaczej 7-zip nie będzie potrafił tego pliku wypakować.

ZipArchive z .NET 4.5 umożliwi ci stworzenie zwykłego pliku .zip. Jeżeli nie możesz z niej skorzystać masz do tego dość popularną bibliotekę SharpZipLib.

0

Do tej pory próbowałem zrobić to w taki sposób testowo do pliku, ale archiwum nie da się rozpakować. Za bardzo nie wiem gdzie mam nadać nazwę pliku xml.

 [Serializable]
    public class Car
    {
        public int MaxSpeed = 100;
        public int DoorCount = 10;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Car c = new Car();
            
            using(MemoryStream ms = new MemoryStream())
            using(FileStream fs = File.Create("ziped.gz"))
            {
                using (GZipStream zip = new GZipStream(ms, CompressionLevel.Optimal, true))
                {
                    XmlSerializer xml = new XmlSerializer(typeof(Car));
                    xml.Serialize(zip, c);
                }
                ms.CopyTo(fs);
            }  
            Console.ReadLine();
        }  
    }
2

ms.CopyTo(fs); nie kopiuje niczego, bo wskaźnik w ms jest ustawiony na koniec strumienia. Przed tym wywołaj ms.Seek(0, SeekOrigin.Begin);.

Za bardzo nie wiem gdzie mam nadać nazwę pliku xml.

Nigdzie. W ten sposób kompresujesz tylko jeden plik, ciąg bajtów. I nic więcej. To nie jest archiwum zip. To odpowiednik skompresowania całego archiwum tar.

Nazywając wynikowy plik w postaci nazwa.xml.gz 7-zip zdekompresowanemu plikowi nada nazwę nazwa.xml.

Jeżeli chcesz uzyskać normalne archiwum zip to użyj wcześniej wspomnianego ZipArchive albo SharpZipLib.

0

Udało mi się za pomocą GZip i ZipArchive uzyskać to co chciałem. Teraz jednak chciał bym wpakować dwa pliki do archiwum, robię to według przykładu ze strony ale za cholerę nie chce działać. Po spakowaniu, nie da się rozpakować archiwum poprzez 7-Zip.

public static void Zip(Car c)
{
    using (MemoryStream ms = new MemoryStream())
    using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
    {
        XmlSerializer xml = new XmlSerializer(typeof(Car));
        ZipArchiveEntry firstEntry = zip.CreateEntry("firstEntry.xml");
        using (Stream firstEntryStream = firstEntry.Open())
        {        
            xml.Serialize(firstEntryStream, c);
        }

        ZipArchiveEntry secondEntry = zip.CreateEntry("secondEntry.xml");
        using (Stream secondEntryStream = secondEntry.Open())
        {
            xml.Serialize(secondEntryStream, c);
        }

        using (var fs = new FileStream("test.zip", FileMode.Create))
        {
            ms.Seek(0, SeekOrigin.Begin);
            ms.CopyTo(fs);
        }
    }
}
1
using (MemoryStream ms = new MemoryStream())
{
    using (ZipArchive zip = new ZipArchive(ms, ZipArchiveMode.Create, true))
    {
        XmlSerializer xml = new XmlSerializer(typeof(Car));
        ZipArchiveEntry firstEntry = zip.CreateEntry("firstEntry.xml");
        using (Stream firstEntryStream = firstEntry.Open())
        {
            xml.Serialize(firstEntryStream, c);
        }

        ZipArchiveEntry secondEntry = zip.CreateEntry("secondEntry.xml");
        using (Stream secondEntryStream = secondEntry.Open())
        {
            xml.Serialize(secondEntryStream, c);
        }
    }

    using (var fs = new FileStream("test.zip", FileMode.Create))
    {
        ms.Seek(0, SeekOrigin.Begin);
        ms.CopyTo(fs);
    }
}

W momencie gdy zapisujesz archiwum na dysk nie jest ono jeszcze kompletne. Zapewne w Dispose zapisywane są jeszcze jakieś metadane (do Central directory file header).

0

Wszystko działa, dzięki za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1