【发布时间】:2019-05-08 03:23:33
【问题描述】:
(尚未回答 - 至少有 3 个解决方案留在那里,而不是原来的问题。)
我一直在尝试解析和拆分大 JSON,但不想修改内容。
在 FloatParseHandling 发生变化之前,浮点转换会更改数字。
与使用普通 Stream.ReadToEnd -> 耗尽或耗尽空闲 RAM -> 崩溃或“停止”方法的 30 秒/5-7GB 相比,类似的循环可以仅使用 14MB 的 RAM 在 40 秒内拆分我机器上的 1/4GB JSON。
当时也想通过二进制比较来验证结果,但是很多数字都变了。
jsonReader.FloatParseHandling = FloatParseHandling.Decimal;
using Newtonsoft.Json; // intentionally ugly - complete working code
long batchSize = 500000, start = 0, end = 0, pos = 0;
bool neverEnd = true;
while (neverEnd) {
end = start + batchSize - 1;
var sr = new StreamReader(File.Open("bigOne.json", FileMode.Open, FileAccess.Read));
var sw = new StreamWriter(new FileStream(@"PartNo" + start + ".json", FileMode.Create));
using (JsonWriter writer = new JsonTextWriter(sw))
using (var jsonR = new JsonTextReader(sr)) {
jsonR.FloatParseHandling = FloatParseHandling.Decimal;
while (neverEnd) {
neverEnd &= jsonR.Read();
if (jsonR.TokenType == JsonToken.StartObject
&& jsonR.Path.IndexOf("BigArrayPathStart") == 0) { // batters[0] ... batters[3]
if (pos > end) break;
if (pos++ < start) {
do { jsonR.Read(); } while (jsonR.TokenType != JsonToken.EndObject);
continue;
}
}
if (jsonR.TokenType >= JsonToken.PropertyName){ writer.WriteToken(jsonR); }
else if (jsonR.TokenType == JsonToken.StartObject) { writer.WriteStartObject(); }
else if (jsonR.TokenType == JsonToken.StartArray) { writer.WriteStartArray(); }
else if (jsonR.TokenType == JsonToken.StartConstructor) {
writer.WriteStartConstructor(jsonR.Value.ToString());
}
}
start = pos; pos = 0;
}
}
【问题讨论】:
-
您为什么要这样做?考虑到您正在处理 "big" JSON 数据,
more efficient以这样的方式对您的应用程序进行编码以便您不必必须 "重新读取 [token]" 并遇到潜在的重复字符串操作和/或对 .NET GC 的影响 -
您可以很好地提出一个好问题,您应该编辑您的问题并:A) 添加一个描述错误行为的示例 json 输入。 B)将相关的解析代码添加到问题本身。 C) 避免在同一篇文章中提出多个不同的问题。
-
for '浮点转换改变数字'。有一个参数可以选择默认的十进制值类型,从浮点数到十进制。但是结果对象中的类型总是很普遍,所以如果你有正确的对象表示,就不应该有错误。 FloatParseHandling 上的 Json.net 文档
-
很可能该文件已在精度损失的情况下生成。这里的根本问题是浮点数是一个近似值。
-
这种方法不经常使用或记录,所以有人可能想选择那种速度较慢但内存很小的方法,这就是我将整个代码放在这里的原因(默认情况下更喜欢 32b 你最终会例如@4GB 崩溃)...
标签: c#