2015-10-05 89 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); 
    } 
} 
相關問題