¿Cómo analizar un archivo JSON enorme como flujo en Json.NET?

¿Cómo analizar un archivo JSON enorme como flujo en Json.NET?

Esto debería resolver su problema. Básicamente, funciona como su código inicial, excepto que solo está deserializando el objeto cuando el lector presiona el { carácter en la secuencia y, de lo contrario, salta al siguiente hasta que encuentra otro token de objeto de inicio.

JsonSerializer serializer = new JsonSerializer();
MyObject o;
using (FileStream s = File.Open("bigfile.json", FileMode.Open))
using (StreamReader sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
    while (reader.Read())
    {
        // deserialize only when there's "{" character in the stream
        if (reader.TokenType == JsonToken.StartObject)
        {
            o = serializer.Deserialize<MyObject>(reader);
        }
    }
}

Creo que podemos hacerlo mejor que la respuesta aceptada, usando más funciones de JsonReader para hacer una solución más generalizada.

Como un JsonReader consume tokens de un JSON, la ruta se registra en el JsonReader.Path propiedad.

Podemos usar esto para seleccionar con precisión datos profundamente anidados de un archivo JSON, usando expresiones regulares para asegurarnos de que estamos en el camino correcto.

Entonces, usando el siguiente método de extensión:

public static class JsonReaderExtensions
{
    public static IEnumerable<T> SelectTokensWithRegex<T>(
        this JsonReader jsonReader, Regex regex)
    {
        JsonSerializer serializer = new JsonSerializer();
        while (jsonReader.Read())
        {
            if (regex.IsMatch(jsonReader.Path) 
                && jsonReader.TokenType != JsonToken.PropertyName)
            {
                yield return serializer.Deserialize<T>(jsonReader);
            }
        }
    }
}

Los datos que le preocupan se encuentran en las rutas:

[0]
[1]
[2]
... etc

Podemos construir la siguiente expresión regular para que coincida con precisión con esta ruta:

var regex = new Regex(@"^\[\d+\]$");

ahora es posible transmitir objetos fuera de sus datos (sin cargar o analizar completamente el JSON completo) de la siguiente manera

IEnumerable<MyObject> objects = jsonReader.SelectTokensWithRegex<MyObject>(regex);

O si queremos profundizar aún más en la estructura, podemos ser aún más precisos con nuestra expresión regular

var regex = new Regex(@"^\[\d+\]\.value$");
IEnumerable<string> objects = jsonReader.SelectTokensWithRegex<string>(regex);

para extraer solo value propiedades de los elementos de la matriz.

Encontré esta técnica extremadamente útil para extraer datos específicos de volcados JSON enormes (100 GiB), directamente desde HTTP usando un flujo de red (con requisitos de memoria bajos y sin necesidad de almacenamiento intermedio).