2015-10-05 44 views
5

我的应用程序使用Json.Net序列化一个对象,压缩生成的JSON,然后将其保存到文件中。另外,应用程序可以从这些文件之一加载对象。这些对象可以在大小几十MB,我很担心内存使用情况,由于道路现有的代码创建大型字符串和字节数组: -我可以使用流对文件进行解压缩和反序列化吗?

public void Save(MyClass myObject, string filename) 
{ 
    var json = JsonConvert.SerializeObject(myObject); 
    var bytes = Compress(json); 
    File.WriteAllBytes(filename, bytes); 
} 

public MyClass Load(string filename) 
{  
    var bytes = File.ReadAllBytes(filename); 
    var json = Decompress(bytes); 
    var myObject = JsonConvert.DeserializeObject<MyClass>(json); 
} 

private static byte[] Compress(string s) 
{ 
    var bytes = Encoding.Unicode.GetBytes(s); 

    using (var ms = new MemoryStream()) 
    { 
     using (var gs = new GZipStream(ms, CompressionMode.Compress)) 
     { 
      gs.Write(bytes, 0, bytes.Length); 
      gs.Close(); 
      return ms.ToArray(); 
     } 
    } 
} 

private static string Decompress(byte[] bytes) 
{ 
    using (var msi = new MemoryStream(bytes)) 
    { 
     using (var mso = new MemoryStream()) 
     { 
      using (var gs = new GZipStream(msi, CompressionMode.Decompress)) 
      { 
       gs.CopyTo(mso); 
       return Encoding.Unicode.GetString(mso.ToArray()); 
      } 
     } 
    } 
} 

我在想,如果在保存/载入的方法可以被流替换?我已经找到了与Json.Net一起使用流的例子,但我正在努力弄清楚如何适应额外的压缩内容。

+1

这可能成为吸引您http://benfoster.io/blog/aspnet-web-api-compression –

+0

@Roy我最近看到的OOM异常,这段代码似乎是合乎逻辑的罪魁祸首。我正在等待VS内存分析器完成生成报告(这么慢......),所以我很快就会有一个更好的主意,但是我认为我会在重新编写代码的同时重新编排我的拇指! –

+0

@AndrewStephens啊goodo。也许在问题中提到你的OOM。祝你好运! – MickyD

回答

5

JsonSerializer有从JsonTextReaderStreamWriter序列化的方法,这两种方法都可以在任何种类的流的顶部创建,包括GZipStream。使用它们,您可以创建以下扩展方法:

public static class JsonExtensions 
{ 
    public static void SerializeToFileCompressed(object value, string path, JsonSerializerSettings settings = null) 
    { 
     using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read)) 
      SerializeCompressed(value, fs, settings); 
    } 

    public static void SerializeCompressed(object value, Stream stream, JsonSerializerSettings settings = null) 
    { 
     using (var compressor = new GZipStream(stream, CompressionMode.Compress)) 
     using (var writer = new StreamWriter(compressor)) 
     { 
      var serializer = JsonSerializer.CreateDefault(settings); 
      serializer.Serialize(writer, value); 
     } 
    } 

    public static T DeserializeFromFileCompressed<T>(string path, JsonSerializerSettings settings = null) 
    { 
     using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) 
      return DeserializeCompressed<T>(fs, settings); 
    } 

    public static T DeserializeCompressed<T>(Stream stream, JsonSerializerSettings settings = null) 
    { 
     using (var compressor = new GZipStream(stream, CompressionMode.Decompress)) 
     using (var reader = new StreamReader(compressor)) 
     using (var jsonReader = new JsonTextReader(reader)) 
     { 
      var serializer = JsonSerializer.CreateDefault(settings); 
      return serializer.Deserialize<T>(jsonReader); 
     } 
    } 
} 

请参阅Json.NET文档中的Performance Tips: Optimize Memory Usage

+1

好东西。我正在混淆不同的阅读器和流应该如何嵌套。重构使用此代码已导致内存使用量的显着改善。 –

1

对于那些正在寻找如何在uwp应用程序中使用@dbc扩展的想法,我将代码修改为此 - StorageFile是您有权写入的文件。

public static async void SerializeToFileCompressedAsync(object value, StorageFile file, JsonSerializerSettings settings = null) 
{ 
    using (var stream = await file.OpenStreamForWriteAsync()) 
     SerializeCompressed(value, stream, settings); 
} 

public static void SerializeCompressed(object value, Stream stream, JsonSerializerSettings settings = null) 
{ 
    using (var compressor = new GZipStream(stream, CompressionMode.Compress)) 
    using (var writer = new StreamWriter(compressor)) 
    { 
     var serializer = JsonSerializer.CreateDefault(settings); 
     serializer.Serialize(writer, value); 
    } 
} 

public static async Task<T> DeserializeFromFileCompressedAsync<T>(StorageFile file, JsonSerializerSettings settings = null) 
{ 
    using (var stream = await file.OpenStreamForReadAsync()) 
     return DeserializeCompressed<T>(stream, settings); 
} 

public static T DeserializeCompressed<T>(Stream stream, JsonSerializerSettings settings = null) 
{ 
    using (var compressor = new GZipStream(stream, CompressionMode.Decompress)) 
    using (var reader = new StreamReader(compressor)) 
    using (var jsonReader = new JsonTextReader(reader)) 
    { 
     var serializer = JsonSerializer.CreateDefault(settings); 
     return serializer.Deserialize<T>(jsonReader); 
    } 
} 
相关问题