11

Json.netには、次のようにオブジェクトをjsonに変換するための非同期関数があります。

json = await JsonConvert.DeserializeObjectAsync<T>

しかし、オブジェクトをjsonファイルに書き込みたい場合は、ファイルStreamを使用して直接書き込む方がよいようです。

だから私はそれがこのようなものでなければならないと思います:

 var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite);

    using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
    {
        using (StreamWriter sw = new StreamWriter(fileStream.AsStreamForWrite()))
        {
            using (JsonWriter jw = new JsonTextWriter(sw))
            {
                jw.Formatting = Formatting.Indented;

                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(jw, obj);
            }
        }

しかし、JsonSerzializerオブジェクトでは、非同期メソッドが見つかりません。また、IO操作を独自のスレッドに配置するべきではないと思います。

推奨されるアプローチは何ですか?

4

3 に答える 3

16

Json.NETは、非同期の逆/シリアル化を実際にはサポートしていません。の非同期メソッドJsonConvertは、別のスレッドでそれらを実行する同期メソッドの単なるラッパーです(これはまさにライブラリが実行すべきではないことです)。

ここでの最善のアプローチは、別のスレッドでファイルアクセスコードを実行することだと思います。これは(スレッドを浪費する)の完全な利点を提供しませんasyncが、UIスレッドをブロックすることはありません。

于 2013-03-26T21:55:14.980 に答える
9

正しい非同期方法を使用するこのコードも参照してください(たとえば、LOHメモリの割り当てを回避するために巨大なバイト配列を作成せず、IO操作が完了するのを待ちません)。

// create this in the constructor, stream manages can be reused
// see details in this answer https://stackoverflow.com/a/42599288/185498
var streamManager = new RecyclableMemoryStreamManager();

using (var file = File.Open(destination, FileMode.Create))
{
    using (var memoryStream = streamManager.GetStream()) // RecyclableMemoryStream will be returned, it inherits MemoryStream, however prevents data allocation into the LOH
    {
        using (var writer = new StreamWriter(memoryStream))
        {
            var serializer = JsonSerializer.CreateDefault();

            serializer.Serialize(writer, data);

            await writer.FlushAsync().ConfigureAwait(false);

            memoryStream.Seek(0, SeekOrigin.Begin);

            await memoryStream.CopyToAsync(file).ConfigureAwait(false);
        }
    }

    await file.FlushAsync().ConfigureAwait(false);
}

ファイル全体:https ://github.com/imanushin/AsyncIOComparison/blob/0e2527d5c00c2465e8fd2617ed8bcb1abb529436/IntermediateData/FileNames.cs

于 2016-03-09T08:36:16.027 に答える
0

JSON.NET/Newtonsoft.JSONではそれを行うことはできません。
ただし、代わりにSystem.Text.Jsonを使用できます。
JSON.NETと同じ動作を得るには、IncludeFieldsとPropertyNameCaseInsensitiveをtrueに設定するだけです。

public static class JsonExtensions
{
    private static readonly System.Text.Json.JsonSerializerOptions _jsonOptions = 
        new System.Text.Json.JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            IncludeFields = true
        }
    ;


    public static string ToJson<T>(this T obj)
    {
        return System.Text.Json.JsonSerializer.Serialize<T>(obj, _jsonOptions);
    }


    public static T FromJson<T>(this string json)
    {
        return System.Text.Json.JsonSerializer.Deserialize<T>(json, _jsonOptions);
    }


    public static async System.Threading.Tasks.Task ToJsonAsync<T>(this T obj, System.IO.Stream stream)
    {
        await System.Text.Json.JsonSerializer.SerializeAsync(stream, obj, typeof(T), _jsonOptions);
    }


    public static async System.Threading.Tasks.Task<T> FromJsonAsync<T>(this System.IO.Stream stream)
    {
        return await System.Text.Json.JsonSerializer.DeserializeAsync<T>(stream, _jsonOptions);
    }

}

そこに行きます。

また、非同期で文字列にシリアル化する場合は、次のようにします。

public static async System.Threading.Tasks.Task<string> ToJsonAsync<T>(this T obj)
{
    string ret = null;

    Microsoft.IO.RecyclableMemoryStreamManager streamManager = 
        new Microsoft.IO.RecyclableMemoryStreamManager();
    
    using (System.IO.MemoryStream ms = streamManager.GetStream())
    {
        await System.Text.Json.JsonSerializer.SerializeAsync(ms, obj, typeof(T), _jsonOptions);
        ms.Position = 0;

        using (System.IO.TextReader sr = new System.IO.StreamReader(ms, System.Text.Encoding.UTF8))
        {
            ret = await sr.ReadToEndAsync();
        }

    }

    return ret;
}
于 2021-09-28T12:10:48.063 に答える