如何在Windows Phone 7上解压缩LZMA压缩zip文件?

时间:2012-03-04 08:05:49

标签: windows-phone-7 deflate zipfile compression lzma

我正在开发一个使用本地SQLite数据库的Windows Phone 7项目。数据库是未压缩的~40MB,所以我使用最大压缩(Deflate)将其压缩到~20MB。这是我的代码(工作)。


    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();
    }

20MB是一个很好的改进,但我注意到使用最大压缩(LZMA)的7z存档实现了大约12MB的文件大小。 zip文件格式支持LZMA内容,因此我将Deflate压缩zip文件切换为LZMA压缩zip文件和 bang 。我得到NullReferenceException:Application.GetResourceStream(...)返回null。据推测,该实现并不能处理LZMA内容。

我尝试了另一个库但是虽然它适用于Deflated zip,但它在LZMA zip上再次失败(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,虽然有一些声称支持LZMA解​​压缩的C#库,但它们与我的Windows Phone项目不兼容(我认为由于已经为.NET3或.NET4设置了但是不是.NET3.5)。

我考虑过使用LZMA SDK实现ICSharpCode.SharpZipLib.LZMA类,但在我重新发明任何轮子之前,我想我应该问一下是否有人在Windows Phone上成功解压缩了LZMA拉链?

任何帮助都非常感激。

1 个答案:

答案 0 :(得分:2)

我继续寻找LZMA解​​压缩的Windows Phone实现,但没有运气,所以我根据LZMA SDK版本9.22测试版制作了一个。在此处发布详细信息,以防有人发现它有用(当然不做任何保证)。

项目来源可以在这里找到: https://github.com/larryk78/SevenZip.Compression.LZMA.WindowsPhone/

该实现提供了三种解压缩方案(我还没有考虑压缩):

  1. StreamDecoder包装SevenZip.Compression.LZMA.Decoder(来自SDK)并提供流到流的解压缩。
  2. IsolatedStorageDecoder扩展StreamDecoder以从IsolatedStorage中的流或文件解压缩到IsolatedStorage中的文件;即分别为流到文件和文件到文件。
  3. WebClient2IsolatedStorageDecoder扩展IsolatedStorageDecoder以从Uri下载压缩文件,然后将其解压缩到IsolatedStorage中的文件。
  4. N.B。 StreamDecoder实现为BackgroundWorker,因此解压缩工作是异步完成的(不会阻止UI线程),并且进度可以连接到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 :)
    }
    

    如果您尝试,请告诉我。没有什么比真实用户的反馈更好:)

    干杯, 拉里

    P.S。此库不处理* .zip文件。它适用于LZMA压缩文件,即* .lzma。您可以使用LZMA SDK中的lzma.exe(二进制文件也在上面链接的github存储库中)制作这些文件。我和ICSharpCode.SharpZipLib库的维护者聊了一下关于将LZMA集成到那里的问题,他很敏感所以让我们看看那里发生了什么......