在 C# 中解码大型 JSON 文件

本文关键字:JSON 文件 大型 解码 | 更新日期: 2023-09-27 17:56:41

从暴雪(一个 6 MB JSON 文件)下载拍卖数据时,在解码时,我能够将错误追溯到:

"使用 JSON JavaScriptSerializer 进行序列化或反序列化期间出错。字符串的长度超过了在 maxJsonLength 属性上设置的值。''r'参数名称:输入"

如何在下面的类中将 maxJsonLength 更改为 20 MB(因为我解析的一些 JSON 可能很大)?

public sealed class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
        return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
    }
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
    }
    #region Nested type: DynamicJsonObject
    private sealed class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _dictionary;
        public DynamicJsonObject(IDictionary<string, object> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            _dictionary = dictionary;
        }
        public override string ToString()
        {
            var sb = new StringBuilder("{");
            ToString(sb);
            return sb.ToString();
        }
        private void ToString(StringBuilder sb)
        {
            var firstInDictionary = true;
            foreach (var pair in _dictionary)
            {
                if (!firstInDictionary)
                    sb.Append(",");
                firstInDictionary = false;
                var value = pair.Value;
                var name = pair.Key;
                if (value is string)
                {
                    sb.AppendFormat("{0}:'"{1}'"", name, value);
                }
                else if (value is IDictionary<string, object>)
                {
                    new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
                }
                else if (value is ArrayList)
                {
                    sb.Append(name + ":[");
                    var firstInArray = true;
                    foreach (var arrayValue in (ArrayList)value)
                    {
                        if (!firstInArray)
                            sb.Append(",");
                        firstInArray = false;
                        if (arrayValue is IDictionary<string, object>)
                            new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                        else if (arrayValue is string)
                            sb.AppendFormat("'"{0}'"", arrayValue);
                        else
                            sb.AppendFormat("{0}", arrayValue);
                    }
                    sb.Append("]");
                }
                else
                {
                    sb.AppendFormat("{0}:{1}", name, value);
                }
            }
            sb.Append("}");
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (!_dictionary.TryGetValue(binder.Name, out result))
            {
                // Return null to avoid exception. The caller can check for null this way...
                result = null;
                return true;
            }
            result = WrapResultObject(result);
            return true;
        }
        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            if (indexes.Length == 1 && indexes[0] != null)
            {
                if (!_dictionary.TryGetValue(indexes[0].ToString(), out result))
                {
                    // Return null to avoid exception. The caller can check for null this way...
                    result = null;
                    return true;
                }
                result = WrapResultObject(result);
                return true;
            }
            return base.TryGetIndex(binder, indexes, out result);
        }
        private static object WrapResultObject(object result)
        {
            var dictionary = result as IDictionary<string, object>;
            if (dictionary != null)
                return new DynamicJsonObject(dictionary);
            var arrayList = result as ArrayList;
            if (arrayList != null && arrayList.Count > 0)
            {
                return arrayList[0] is IDictionary<string, object>
                    ? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)))
                    : new List<object>(arrayList.Cast<object>());
            }
            return result;
        }
    }
    #endregion
}

或者在调用方法中:

    public static dynamic DecodeJson(this string str)
    {
        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
        dynamic result = null;
        try
        {
            result = serializer.Deserialize(str, typeof(object));
        } catch (ArgumentException ae)
        {
            Log.Output(ae.InnerException.Message);
        }
        return result;
    }

在 C# 中解码大型 JSON 文件

你应该修改 JavaScriptSerializer.MaxJsonLength 属性

JSON 字符串的最大长度。默认值为 2097152 个字符, 相当于 4 MB 的 Unicode 字符串数据。

public static dynamic DecodeJson(this string str)
{
    var serializer = new JavaScriptSerializer();
    serializer.MaxJsonLength = Int.MaxValue; // The value of this constant is 2,147,483,647
    serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
    dynamic result = null;
    try
    {
        result = serializer.Deserialize(str, typeof(object));
    } catch (ArgumentException ae)
    {
        Log.Output(ae.InnerException.Message);
    }
    return result;
}