C# 我可以使用流对文件进行解压缩和反序列化吗?

C# 我可以使用流对文件进行解压缩和反序列化吗?,c#,stream,json.net,gzipstream,C#,Stream,Json.net,Gzipstream,我的应用程序使用Json.Net序列化对象,压缩生成的Json,然后将其保存到文件中。此外,应用程序可以从这些文件之一加载对象。这些对象的大小可以达到数十Mb,我关心的是内存使用情况,因为现有代码创建大型字符串和字节数组的方式:- public void Save(MyClass myObject, string filename) { var json = JsonConvert.SerializeObject(myObject); var bytes = Compress(j

我的应用程序使用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());
            }
        }
    } 
}
public void保存(MyClass myObject,字符串文件名)
{
var json=JsonConvert.SerializeObject(myObject);
var bytes=Compress(json);
File.writealBytes(文件名,字节);
}
公共MyClass加载(字符串文件名)
{    
var bytes=File.ReadAllBytes(文件名);
var json=解压缩(字节);
var myObject=JsonConvert.DeserializeObject(json);
}
私有静态字节[]压缩(字符串s)
{
var bytes=Encoding.Unicode.GetBytes;
使用(var ms=new MemoryStream())
{
使用(var gs=new GZipStream(ms,CompressionMode.Compress))
{
写入(字节,0,字节长度);
gs.Close();
返回ToArray女士();
}
}
}
专用静态字符串解压缩(字节[]字节)
{
使用(var msi=新内存流(字节))
{
使用(var mso=new MemoryStream())
{
使用(var gs=new GZipStream(msi,CompressionMode.decompresse))
{
一般事务副秘书长(mso);
返回Encoding.Unicode.GetString(mso.ToArray());
}
}
} 
}
我想知道是否可以用流替换Save/Load方法?我已经找到了将流与Json.Net结合使用的例子,但我正在努力弄清楚如何适应额外的压缩内容。

有从和序列化到的方法,这两种方法都可以在任何类型的流之上创建,包括
GZipStream
。使用它们,可以创建以下扩展方法:

public static partial class JsonExtensions
{
    // Buffer sized as recommended by Bradley Grainger, https://faithlife.codes/blog/2012/06/always-wrap-gzipstream-with-bufferedstream/
    // But anything smaller than 85,000 bytes should be OK, since objects larger than that go on the large object heap.  See:
    // https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap
    const int BufferSize = 8192;
    // Disable writing of BOM as per https://datatracker.ietf.org/doc/html/rfc8259#section-8.1
    static readonly Encoding DefaultEncoding = new UTF8Encoding(false);

    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, DefaultEncoding, BufferSize))
        {
            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);
        }
    }
}
公共静态部分类JsonExtensions
{
//缓冲区大小符合Bradley Grainger的建议,https://faithlife.codes/blog/2012/06/always-wrap-gzipstream-with-bufferedstream/
//但是任何小于85000字节的都可以,因为大于85000字节的对象都会在大型对象堆上。请参阅:
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap
const int BufferSize=8192;
//根据禁用BOM的写入https://datatracker.ietf.org/doc/html/rfc8259#section-8.1
静态只读编码DefaultEncoding=新的UTF8Encoding(false);
public static void SerializeToFileCompressed(对象值、字符串路径、JsonSerializerSettings=null)
{
使用(var fs=newfilestream(路径,FileMode.Create,FileAccess.Write,FileShare.Read))
序列化压缩(值、fs、设置);
}
public static void serialized compressed(对象值、流、JsonSerializerSettings设置=null)
{
使用(var compressor=new GZipStream(stream,CompressionMode.Compress))
使用(var writer=newstreamwriter(压缩器、DefaultEncoding、BufferSize))
{
var serializer=JsonSerializer.CreateDefault(设置);
serializer.Serialize(writer,value);
}
}
公共静态T反序列化FromFileCompressed(字符串路径,JsonSerializerSettings=null)
{
使用(var fs=new FileStream(路径,FileMode.Open,FileAccess.Read,FileShare.Read))
返回反序列化压缩(fs、设置);
}
公共静态T反序列化压缩(流,JsonSerializerSettings=null)
{
使用(var compressor=new GZipStream(stream,CompressionMode.decompresse))
使用(变量读取器=新的流读取器(压缩机))
使用(var jsonReader=newjsontextreader(reader))
{
var serializer=JsonSerializer.CreateDefault(设置);
返回序列化程序。反序列化(jsonReader);
}
}
}

请参阅Json.NET文档。

对于那些想了解如何在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);
    }
}
public static async void SerializeToFileCompressedAsync(对象值、存储文件、JsonSerializerSettings=null)
{
使用(var stream=await file.OpenStreamForWriteAsync())
序列化压缩(值、流、设置);
}
public static void serialized compressed(对象值、流、JsonSerializerSettings设置=null)
{
使用(var compressor=new GZipStream(stream,CompressionMode.Compress))
使用(var编写器=新的StreamWriter(压缩机))
{
var serializer=JsonSerializer.CreateDefault(设置);
serializer.Serialize(writer,value);
}
}
公共静态异步任务反序列化FromFileCompressedAsync(存储文件文件,JsonSerializerSettings=null)
{
使用(var stream=await file.OpenStreamForReadAsync())
返回反序列化压缩(流、设置);
}
公共静态T反序列化压缩(流,JsonSerializerSettings=null)
{
使用(var compressor=new GZipStream(stream,CompressionMode.decompresse))
使用(变量读取器=新的流读取器(压缩机))
使用(var jsonReader=newjsontextreader(reader))
{
var serializer=JsonSerializer.CreateDefault(设置);
返回序列化程序。反序列化(jsonReader);
}
}

这可能会让你感兴趣@Roy我最近看到OOM异常,这段代码似乎是罪魁祸首。我正在等待VS memory profiler完成报告的生成(太慢了…),所以我很快就会有更好的主意,但我想我会在玩弄大拇指的时候尝试重构这段代码@安德鲁斯塔芬斯:太好了。也许在问题中提到你的房间。祝你好运好东西。我搞混了各种阅读器和流应该如何嵌套。重构以使用此代码已导致substa