【发布时间】:2019-11-13 21:27:10
【问题描述】:
当我得到一个非常大的文本数据并且每行包含一些元数据 + json 数据字符串时,我有一个案例。 我需要处理每一行的json数据。
这就是我所拥有的:
public Data GetData(string textLine)
{
var spanOfLine = textLine.AsSpan();
var indexOfComma = spanOfLine.IndexOf(":");
var dataJsonStringAsSpan = spanOfLine.Slice(indexOfComma + 1);
// now use dataJsonStringAsSpan which is ReadOnlySpan<char> to deserialize the Data
}
Data 是一个 Dto 类,它有一堆 (7) 个不同的属性:
public class Data
{
public int Attribute1 { get; set; }
public double Attribute2 { get; set; }
// ... more properties, emitted for the sake of brevity
}
我正在尝试使用System.Text.Json API 来实现这一点。令人惊讶的是它没有从ReadOnlySpan<char> 反序列化的任何重载,所以我想出了这个:
public Data GetData(string textLine)
{
var spanOfLine = textLine.AsSpan();
var indexOfComma = spanOfLine.IndexOf(":");
var dataJsonStringAsSpan = spanOfLine.Slice(indexOfComma + 1);
var byteCount = Encoding.UTF8.GetByteCount(dataJsonStringAsSpan);
Span<byte> buffer = stackalloc byte[byteCount];
Encoding.UTF8.GetBytes(dataJsonStringAsSpan, buffer);
var data = JsonSerializer.Deserialize<Data>(buffer);
return data;
}
虽然这可行,但看起来非常复杂。
这是要走的路还是我错过了更简单的东西?
【问题讨论】:
-
是否有特殊原因需要将每行文本转换为跨度..?字符串在 json api 中更容易使用和原生工作,如果你已经得到了一个字符串,为什么不直接取包含 json 数据的子字符串呢?
-
如果您的文本“非常大”并且您不想为其创建 String 对象,那么您 - 绝对 - 不想要 stackalloc。您可以反序列化
dataJsonStringAsSpan.ToString()(ReadOnlySpan<char>上的 ToString 是“将这些内容复制到字符串”,而不是“作为调试辅助/显示值”) -
您能否请edit 分享您尝试反序列化的 JSON 的(简化)示例?此外,如果您的 JSON 非常大,那么您一开始就不想将其加载到单个
string中,它将继续在大型对象堆上,并可能消除您从中获得的任何优势使用System.Text.Json。 (也许我理解错了,每个textLine不是很大?)您是从本地文件、HTTP 响应还是其他文件中读取 JSON? -
如果你绝对需要最小化内存压力,你可以看看微软如何实现
Deserialize(string json, Type returnType, JsonSerializerOptions options = null)here。 -
看起来您可以使用附加参数
int start, int length创建您自己的代码版本,并将这些参数传递给AsSpan(string, int, int)。您还需要来自JsonReaderHelper的几种方法的您自己的版本。不确定是否值得。
标签: c# json .net-core json-deserialization system.text.json