【问题标题】:OutOfMemoryException when reading a Json string读取 Json 字符串时出现 OutOfMemoryException
【发布时间】:2016-07-22 20:07:19
【问题描述】:

我正在尝试从大小约为 1.7 GB 的网络提要中反序列化 Json 数据。我从以下代码开始:

public override void CreateNewOutputRows()
{

    //Set Webservice URL
    string wUrl = "webserviceURLgoeshere";

    try
    {

        RootObject outPutResponse = GetWebServiceResult(wUrl);

        foreach (Impression imp in outPutResponse.impressions)
        {

            ImpressionsSheetOutputBuffer.AddRow();
            ImpressionsSheetOutputBuffer.token = imp.token;
            ImpressionsSheetOutputBuffer.userid = imp.userid;
            ImpressionsSheetOutputBuffer.itemid = imp.itemid;
            ImpressionsSheetOutputBuffer.view = imp.view;
            ImpressionsSheetOutputBuffer.imageguid = imp.imageguid;
            ImpressionsSheetOutputBuffer.bytes = imp.bytes;
            ImpressionsSheetOutputBuffer.format = imp.format;

            ImpressionIDBuffer.AddRow();
            ImpressionIDBuffer.oid = imp.imId.oid;

            ImpressionParamsBuffer.AddRow();
            ImpressionParamsBuffer.origformat = imp.imParams.origFormat;
            ImpressionParamsBuffer.size = imp.imParams.size;

            ImpressionTimeBuffer.AddRow();
            ImpressionTimeBuffer.numLong = Int32.Parse(imp.imTime.numLong);
        }
    }

    catch (Exception e)
    {
        FailComponent(e.ToString());
    }
}

private RootObject GetWebServiceResult(string wUrl)
{

    HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create(wUrl);
    HttpWebResponse httpWResp = (HttpWebResponse)httpWReq.GetResponse();
    RootObject jsonResponse = null;

    try
    {

        if (httpWResp.StatusCode == HttpStatusCode.OK)
        {

            Stream responseStream = httpWResp.GetResponseStream();
            string jsonString = null;

            using (StreamReader reader = new StreamReader(responseStream))
            {
                jsonString = reader.ReadToEnd();
                reader.Close();
            }

            JavaScriptSerializer sr = new JavaScriptSerializer();
            jsonResponse = sr.Deserialize<RootObject>(jsonString);

        }

        else
        {
            FailComponent(httpWResp.StatusCode.ToString());

        }
    }

    catch (Exception e)
    {
        FailComponent(e.ToString());
    }
    return jsonResponse;
}

private void FailComponent(string errorMsg)
{
    bool fail = false;
    IDTSComponentMetaData100 compMetadata = this.ComponentMetaData;
    compMetadata.FireError(1, "Error Getting Data From Webservice!", errorMsg, "", 0, out fail);

}

}

public class Id {

    public string oid { get; set; }
}

public class Params {

    public string origFormat { get; set; }
    public string size { get; set; }
}

public class Time {

    public string numLong { get; set; }
}

public class Impression {

    public Id imId { get; set; }
    public string token { get; set; }
    public string userid { get; set; }
    public string itemid { get; set; }
    public string view { get; set; }
    public string imageguid { get; set; }
    public int bytes { get; set; }
    public string format { get; set; }
    public Params imParams { get; set; }
    public Time imTime { get; set; }
}

public class RootObject {
    public List<Impression> impressions { get; set; }
}

但是,StreamReader ReadToEnd 方法是引发异常的地方,因为数据太大。

我尝试将该代码更改为以下内容:

Stream responseStream = httpWResp.GetResponseStream();

StreamReader reader = new StreamReader(responseStream);

using (var myjson = new JsonTextReader(reader))
{
    JsonSerializer myserialization = new JsonSerializer();
    return (List<RootObject>)myserialization.Deserialize(myjson, typeof(List<RootObject>));
}

这给了我一个错误,我无法将类型 List&lt;RootObject&gt; 隐式转换为 RootObject。有没有人看到我可能做错了什么,我无法进行这种转换?我使用this question 绕过OutOfMemory 异常,但现在它不返回反序列化的项目。任何建议将不胜感激。

编辑: Json 数据如下所示:

{
"_id": {
    "$oid": "000000000000000000000000"
    },
"token": "00000000-0000-0000-0000-000000000000",
"userId": "username",
"itemId": "00000000-0000-0000-0000-000000000000",
"view": "view1",
"imageguid": "00000000-0000-0000-0000-000000000000",
"bytes": 1000,
"format": "PNG",
"params": {
    "originalFormat": "tif",
    "size": "50x50"
    },
"time": {
    "$numberLong": "1458748200000"
    }
}
{
"_id": {
    "$oid": "100000000000000000000000"
     },
"token": "00000000-0000-0000-0000-000000000000",
"userId": "username",
"itemId": "00000000-0000-0000-0000-000000000000",
"view": "view1",
"imageguid": "00000000-0000-0000-0000-000000000000",
"bytes": 1000,
"format": "PNG",
"params": {
    "originalFormat": "tif",
    "size": "50x50"
    },
"time": {
    "$numberLong": "1458748200000"
    }
}

【问题讨论】:

  • 64 位应用程序应该可以正常工作。请确保您没有以 x86 运行。
  • ~1.7 GB 看来您的内存不足了。解决方案?不要那样做。如何?更好的设计。像什么?很多东西。给我一个。增量处理文件,不要尝试将其全部加载到内存中。如何。依靠。这就是人们雇用开发人员的原因:/
  • 不要试图一次读完整本书。 StreamReader 的全部意义在于您可以流式传输数据。您不必一次获得全部内容。做 ReadLine 什么的。如果您需要在应用程序获取大量文件时保持响应,请考虑使用 async/await。
  • Anthony,您的示例 JSON 不是有效的 JSON,因为它不能有多个根对象。见here

标签: c# ssis json.net


【解决方案1】:

您应该创建一些规则来分隔每个对象,并分别序列化它们。

基本上你可以追加stream.ReadLine() 18 次(假设所有对象都和你发布的完全一样)

如果不是,您应该使用 stream.ReadLine() 来计算您的左大括号和右大括号,直到您到达每个对象的末尾并以这种方式分别序列化它们。

我猜有更好的方法,但这些方法很简单,应该可以解决您的问题...

【讨论】:

    猜你喜欢
    • 2016-03-29
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多