二进制序列化对象作为文件的压缩级别

Sae*_*ani 0 c# compression binary serialization winforms

在我的应用程序中,我有一个从一些 XML 文件创建的相当大的对象。xml 文件大小约为 30MB,而该 xml 文件中的二进制序列化对象约为 8~9MB。有趣的是,如果我用 WinRar 等压缩这个二进制文件,它只有 1~2MB。

有没有办法提高对象本身的压缩级别?或者我应该通过手动编写代码来使用另一级压缩,以便在保存后压缩文件或在加载回程序之前解压缩文件?

以防万一,这是我用来将对象保存为文件的代码:

    public static bool SaveProject(Project proj, string pathAndName)
    {
        bool success = true;
        proj.FileVersion = CurrentFileVersion;

        try
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(pathAndName, FileMode.Create, FileAccess.Write, FileShare.None);
            formatter.Serialize(stream, proj);
            stream.Close();
        }
        catch (Exception e)
        {
            MessageBox.Show("Can not save project!" + Environment.NewLine + "Reason: ", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

            success = false;
        }

        return success;
    }
Run Code Online (Sandbox Code Playgroud)

更新 我尝试通过添加来更改我的代码GZIPSTREAM,但似乎它没有做任何事情!或者也许我的实现是错误的?

public static bool SaveProject(Project proj, string pathAndName)
{
    bool success = true;
    proj.FileVersion = CurrentFileVersion;

    try
    {
        IFormatter formatter = new BinaryFormatter();
        var stream = new FileStream(pathAndName, FileMode.Create, FileAccess.Write, FileShare.None);
        var gZipStream = new GZipStream(stream, CompressionMode.Compress);
        formatter.Serialize(stream, proj);
        stream.Close();
        gZipStream.Close();
    }
    catch (Exception e)
    {
        MessageBox.Show("Can not save project!" + Environment.NewLine + "Reason: ", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

        success = false;
    }

    return success;
}

public static Project LoadProject(string path)
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
    var gZipStream = new GZipStream(stream, CompressionMode.Decompress);
    var obj = (Project)formatter.Deserialize(gZipStream);
    stream.Close();
    gZipStream.Close();

    if (obj.FileVersion != CurrentFileVersion)
    {
        throw new InvalidFileVersionException("File version belongs to an older version of the program.");
    }

    return obj;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 5

将您的内容包装FileStreamDeflateStreamwith中CompressionMode.Compress- 将其传递给序列化器。然后要反序列化,请将 a包裹FileStream在 a 中。DeflateStreamCompressionMode.Decompress

Close请注意,您应该使用语句,而不是using显式调用,例如

using (FileStream fileStream = ...)
using (DeflateStream deflateStream = new DeflateStream(fileStream, 
                                                      CompressionMode.Compress))
{
    formatter.Serialize(deflateStream, proj);
}
Run Code Online (Sandbox Code Playgroud)

您可以GZipStream以相同的方式使用 - 尝试两者,看看哪一个往往会给您带来更好的压缩(或更好的性能,如果您关心的话)。

请注意这种方法如何将序列化方面与压缩方面分开,将两者组合在一起,同时保持良好的关注点分离。序列化代码只是写入流,而不关心数据会发生什么,而压缩代码只是压缩给定的内容,而不关心数据的含义。

  • 不要按照尊敬的 Jon Skeet 的建议使用 Microsoft 的 .NET GZipSteam 或 DeflateStream 类。请改用 DotNetZip (http://dotnetzip.codeplex.com/)。.NET 类在压缩和完整性检查方面存在严重错误,在此处的答案中指出:http://stackoverflow.com/questions/11435200/why-does-my-c-sharp-gzip-product-a-larger-file -than-fiddler-或-php 。 (4认同)