Как распаковать сжатый ZZ-файл LZMA на Windows Phone 7? - PullRequest
1 голос
/ 04 марта 2012

Я занимаюсь разработкой проекта для Windows Phone 7, в котором используется локальная база данных SQLite. База данных без сжатия ~ 40 МБ, поэтому я сжал ее, используя максимальное сжатие (Deflate) до ~ 20 МБ. Вот мой код (работает).


    private void unzip_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = (BackgroundWorker)sender;
        IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
        IsolatedStorageFileStream file = new IsolatedStorageFileStream(filename, FileMode.Create, store);
        // TODO: switch from Deflate ~18.7MB to LZMA ~12.1MB (original ~41.5MB)
        StreamResourceInfo zipInfo = new StreamResourceInfo((Stream)e.Argument, null);
        StreamResourceInfo streamInfo = Application.GetResourceStream(zipInfo, new Uri(filename, UriKind.Relative));
        long total = streamInfo.Stream.Length;
        long done = 0;
        int size = 32768;
        byte[] data = new byte[size];
        while ((size = streamInfo.Stream.Read(data, 0, data.Length)) > 0)
        {
            file.Write(data, 0, size);
            done += size;
            int percentComplete = (int)(100 * ((float)done / (float)total));
            worker.ReportProgress(percentComplete);
        }
        file.Close();
    }

20 МБ - хорошее улучшение, но я заметил, что архив 7z с максимальным сжатием (LZMA) достигает размера файла ~ 12 МБ. Формат zip-файла поддерживает содержимое LZMA, поэтому я переключил сжатый zip-файл Deflate для сжатого zz-файла LZMA и bang . Я получаю NullReferenceException: Application.GetResourceStream(...) возвращает ноль. Предположительно, эта реализация не обрабатывает содержимое LZMA.

Я попробовал другую библиотеку, но, хотя она отлично работает для zip-файла Deflated, опять-таки происходит сбой на zz-архиве LZMA (NotSupportedException: метод сжатия не поддерживается).


    using ICSharpCode.SharpZipLib.Zip;
    ...
    private void unzip_DoWork(object sender, DoWorkEventArgs e)
    {
    ...
        using (ZipInputStream zip = new ZipInputStream((Stream)e.Argument))
        {
            ZipEntry entry = zip.GetNextEntry(); // consume zip header (required)
            ....
        }
    }

Я посмотрел в NuGet и, хотя есть несколько библиотек C #, которые утверждают, что поддерживают декомпрессию LZMA, они не были совместимы с моим проектом Windows Phone (думаю, из-за того, что он был настроен для .NET3 или .NET4, но нет. NET3.5).

Я думал о реализации класса ICSharpCode.SharpZipLib.LZMA с использованием LZMA SDK, но перед тем, как заново изобретать какие-либо колеса, я подумал, что мне следует спросить, успешно ли кто-нибудь распаковал zip-архив LZMA на Windows Phone?

Любая помощь высоко ценится.

1 Ответ

2 голосов
/ 10 апреля 2012

Я продолжал искать в Windows Phone реализацию декомпрессии LZMA, но безуспешно, поэтому я сделал ее на основе бета-версии LZMA SDK версии 9.22.Размещать детали здесь, если кто-то сочтет это полезным (конечно, без гарантий).

Источник проекта можно найти здесь: https://github.com/larryk78/SevenZip.Compression.LZMA.WindowsPhone/

Реализация предлагает три сценария декомпрессии (я не делал)пока не смотрите на сжатие):

  1. StreamDecoder упаковывает SevenZip.Compression.LZMA.Decoder (из SDK) и предлагает распаковку от потока к потоку.
  2. IsolatedStorageDecoder extends StreamDecoder распаковывать из потока или файла в IsolatedStorage, в файл в IsolatedStorage;то есть поток в файл и файл в файл, соответственно.
  3. WebClient2IsolatedStorageDecoder расширяет IsolatedStorageDecoder, чтобы загрузить сжатый файл из Uri, а затем распаковать его в файл в IsolatedStorage.

NB StreamDecoder реализован в виде BackgroundWorker, поэтому работа по распаковке выполняется асинхронно (не блокирует поток пользовательского интерфейса), а прогресс может быть подключен к ProgressBar.

Вотпример использования WebClient2IsolatedStorageDecoder:

using SevenZip.Compression.LZMA.WindowsPhone;
using System.ComponentModel;

// <Button Content="Click Me!" Click="button_Click" />
private void button_Click(object sender, RoutedEventArgs e)
{
    WebClient2IsolatedStorageDecoder decoder = new WebClient2IsolatedStorageDecoder();
    decoder.ProgressChanged += new ProgressChangedEventHandler(decoder_ProgressChanged);
    decoder.RunWorkerCompleted += new RunWorkerCompletedEventHandler(decoder_RunWorkerCompleted);
    decoder.DecodeAsync(new Uri("http://example.com/compressed_file.lzma"), "decompressed_file.txt");
}

void decoder_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // <ProgressBar x:Name="Progress" />
    Progress.Value = e.ProgressPercentage;
}

void decoder_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error)
    {
        MessageBox.Show("Couldn't download/decompress: " + e.Error.Message);
        return;
    }

    // ...do something with the decompressed data :)
}

Пожалуйста, дайте мне знать, если вы попробуете.Нет ничего лучше, чем отзывы реальных пользователей ™:)

Приветствия, Ларри

PS Эта библиотека не обрабатывает * .zip файлы.Работает на сжатых файлах LZMA, т.е. * .lzma.Вы можете сделать это, используя lzma.exe из LZMA SDK (бинарный файл также находится в репозитории github, см. Выше).Я поговорил с разработчиком библиотеки ICSharpCode.SharpZipLib об интеграции в него LZMA, и он заинтересован, так что давайте посмотрим, что там происходит ...

...