1

我正在开发一个使用本地 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,虽然有一些 C# 库声称支持 LZMA 解压缩,但它们与我的 Windows Phone 项目不兼容(我认为是因为已经为 .NET3 或 .NET4 而不是 .NET3.5 设置了)。

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

非常感谢任何帮助。

4

1 回答 1

2

我继续寻找 LZMA 解压缩的 Windows Phone 实现,但没有运气,所以我基于 LZMA SDK 版本 9.22 beta 制作了一个。在这里发布详细信息以防有人发现它有用(当然没有保证)。

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

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

  1. StreamDecoder包装SevenZip.Compression.LZMA.Decoder(来自 SDK)并提供流到流的解压缩。
  2. IsolatedStorageDecoder扩展StreamDecoder以从IsolatedStorage 中的流或文件解压缩到IsolatedStorage 中的文件;即流到文件和文件到文件,分别。
  3. WebClient2IsolatedStorageDecoder扩展IsolatedStorageDecoder以从 a 下载压缩文件Uri,然后将其解压缩为 IsolatedStorage 中的文件。

NBStreamDecoder被实现为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 :)
}

如果您尝试,请告诉我。没有什么比 Real User™ 反馈更棒了 :)

干杯,拉里

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

于 2012-04-10T13:10:02.350 回答