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

时间:2012-08-24 09:16:57

标签: c# winforms serialization binary compression

在我的应用程序中,我有一个从一些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;
    }

更新 我尝试通过添加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;
}

1 个答案:

答案 0 :(得分:3)

FileStream换成DeflateStream CompressionMode.Compress - 将其传递给序列化程序。然后要反序列化,将FileStream打包在DeflateStream CompressionMode.Decompress

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

using (FileStream fileStream = ...)
using (DeflateStream deflateStream = new DeflateStream(fileStream, 
                                                      CompressionMode.Compress))
{
    formatter.Serialize(deflateStream, proj);
}

您可以以相同的方式使用GZipStream - 尝试两者以查看哪些可以为您提供更好的压缩效果(如果您关心的话,可以提供更好的效果)。

请注意这种方法如何将序列化方面与压缩方面区分开来,在保持良好的关注点分离的同时组合这两者。序列化代码只是写入流而不关心数据发生了什么,压缩代码只是压缩它所给出的内容而不关心数据意味着什么。