我使用以下代码解压缩包含由HttpClient检索的压缩Json提要的本地ZIP文件。
ProgressStream progressStream = null;
API_Json_Special_Feeds.RootObject root = null;
private void import_File(string file)
{
isImporting = true;
Console.WriteLine("Importing " + Path.GetFileName(file));
using (FileStream read = File.OpenRead(file))
{
progressStream = new ProgressStream(read);
using (GZipStream zip = new GZipStream(progressStream, CompressionMode.Decompress))
{
UTF8Encoding temp = new UTF8Encoding(true);
var serializer = new JsonSerializer();
StreamReader sr = new StreamReader(zip);
using (var jsonTextReader = new JsonTextReader(sr))
{
root = serializer.Deserialize<API_Json_Special_Feeds.RootObject>(jsonTextReader);
//I'd like to manipulate root between these lines
foreach (API_Json_Special_Feeds.Item item in root.items)
{
Special_Feed_Data.special_Feed_Items.Add(item);
}
}
progressStream.Dispose();
}
}
}
文件相当大,压缩300-600MB,未压缩9-11GB。如您所见,我插入了一个中间流,以便检查吞吐量。这一切都适用于我的64GB机器,但客户端只有8GB可以使用。尝试在具有8G RAM的机器上解压缩和序列化9-11G并不会很有趣。
我是Json的新手,所以我最初的想法是对数据进行某种过滤或分页,因为它被反序列化,可能与我用来测量流吞吐量的方法相同:< / p>
private void timer()
{
bool isRunning = true;
while (isRunning)
{
if (progressStream != null)
{
kBytes_Read = ((double)progressStream.BytesRead / (double)1024);
mem_Used = get_Memory_Used();
if (root != null)
Console.WriteLine("Root contains " + root.items.Count.ToString() + " items");
//This doesn't work, because root is null until ALL of the data is deserialized
}
Thread.Sleep(450);
}
}
在我看来,我看到Json.net一次反序列化一条记录并将其添加到root中的项目列表中。这样做的问题在于&#34; root&#34;求值为null直到流完成 - 我无法找到访问反序列化数据的方法,直到反序列化方法完成。
问题在反序列化仍在进行中时,有没有办法访问已经序列化为Root.Items的数据?如果没有,那么如何停止/分页/暂停大数据的反序列化以使其不会爆炸?
我感谢您的时间,并提前了解您可以提供的任何想法或建议。
答案 0 :(得分:0)
您必须避免将整个根对象反序列化到内存中。您可以使用相同的JsonTextReader
执行此操作,因为它逐个解析json令牌,但您必须进行一些小的手动解析。这是一个例子:
static void Main(string[] args)
{
// our fake huge object
var json = @"{""root"":{""items"":[{""data"":""value""},{""data"":""value""}]}}";
using (var reader = new JsonTextReader(new StringReader(json))) {
bool insideItems = false;
while (reader.Read()) {
// reading tokens one by one
if (reader.TokenType == JsonToken.PropertyName) {
// remember, this is just an example, so it's quite crude
if ((string) reader.Value == "items") {
// we reached property named "items" of some object. We assume this is "items" of our root object
insideItems = true;
}
}
if (reader.TokenType == JsonToken.StartObject && insideItems) {
// if we reached start of some json object, and we have already reached "items" property before - we assume
// we are inside "items" array
// here, deserialize items one by one. This way you will consume almost no memory at any given time
var item = JsonSerializer.Create().Deserialize<DataItem>(reader);
Console.WriteLine(item.Data);
}
}
}
}
public class DataItem {
public string Data { get; set; }
}
}
请记住,这只是一个例子。在现实生活中,你需要做更仔细的手动解析(检查“items”属性是否确实是你的根对象,检查它是否是一个数组等等),但总的想法是一样的。