2012-08-24 119 views
0

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

UPDATE 我试图通过增加一个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; 
} 
+0

什么不试试'GZipStream邮编=新GZipStream(流,System.IO.Compression.CompressionMode.Compress); formatter.Serialize(zip,proj);'看看。 –

+0

@ L.B Thaks,我试过但文件大小没有变化!请检查更新! –

+0

你仍然序列化为'stream'。使用'gZipStream' ['* formatter.Serialize(stream,proj);''] –

回答

3

包装你FileStreamDeflateStreamCompressionMode.Compress - 传递到串行器。然后进行反序列化,将FileStream换成DeflateStreamCompressionMode.Decompress

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

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

您可以用同样的方式使用GZipStream - 都试一下,看看这往往给你更好的压缩(或更好的性能,如果你关心这一点)。

注意:此方法如何分离压缩方面的系列化方面,组成两个同时保持关注良好的分离。序列化代码只是写入数据流而不关心数据发生了什么,而压缩代码只是压缩数据的内容而不关心数据的含义。

+0

感谢Jon,我必须研究如何使用'Using'语句。但是现在我尝试了'GZipStream',但它什么也没做,你能在我的问题中检查更新吗? –

+0

@ Sean87:它不会执行任何操作,因为您仍在序列化到* FileStream *。你应该有'formatter.Serialize(gzipStream,proj);' –

+0

现在它可以工作,但使用gzip它只能将文件大小从7.7减少到6.8 ....几乎不到1MB!有任何想法吗 ?! –