Читаем большой JSON-массив по одному объекту в C#!
Пусть orders.json содержит тысячи заказов одним массивом. Если загрузить файл целиком через ReadAllText, память займут и исходный текст, и созданные объекты. Для последовательной обработки удобнее читать поток и получать элементы по мере разбора.
Сначала опишем модель входных данных. В примере у каждого заказа есть номер и сумма:
public sealed record Order(int Id, decimal Total);
Откроем файл как поток. JsonSerializer.DeserializeAsyncEnumerable ожидает JSON-массив и возвращает асинхронную последовательность его элементов:
await using var stream = File.OpenRead("orders.json");
var orders = JsonSerializer.DeserializeAsyncEnumerable(
stream, cancellationToken: cancellationToken);
Здесь cancellationToken позволяет прервать длительную обработку, например при остановке запроса или фоновой задачи. Не надо самостоятельно резать JSON на строки, переносы строк не определяют границы объектов.
Обработаем элементы по одному и накопим итог. Нулевые элементы пропустим, а отрицательную сумму считаем ошибкой данных:
decimal total = 0;
await foreach (Order? order in orders) {
if (order is null) continue;
if (order.Total < 0) throw new InvalidDataException("Сумма меньше нуля");
total += order.Total;
}
После завершения цикла в total будет сумма всех валидных заказов. В нужном месте вместо накопления можно отправлять запись в базу. Если важна устойчивость к повторной обработке, используй Id как ключ идемпотентности.
➡️ C# Ready | #практика
Пусть orders.json содержит тысячи заказов одним массивом. Если загрузить файл целиком через ReadAllText, память займут и исходный текст, и созданные объекты. Для последовательной обработки удобнее читать поток и получать элементы по мере разбора.
Сначала опишем модель входных данных. В примере у каждого заказа есть номер и сумма:
public sealed record Order(int Id, decimal Total);
Откроем файл как поток. JsonSerializer.DeserializeAsyncEnumerable ожидает JSON-массив и возвращает асинхронную последовательность его элементов:
await using var stream = File.OpenRead("orders.json");
var orders = JsonSerializer.DeserializeAsyncEnumerable(
stream, cancellationToken: cancellationToken);
Здесь cancellationToken позволяет прервать длительную обработку, например при остановке запроса или фоновой задачи. Не надо самостоятельно резать JSON на строки, переносы строк не определяют границы объектов.
Обработаем элементы по одному и накопим итог. Нулевые элементы пропустим, а отрицательную сумму считаем ошибкой данных:
decimal total = 0;
await foreach (Order? order in orders) {
if (order is null) continue;
if (order.Total < 0) throw new InvalidDataException("Сумма меньше нуля");
total += order.Total;
}
После завершения цикла в total будет сумма всех валидных заказов. В нужном месте вместо накопления можно отправлять запись в базу. Если важна устойчивость к повторной обработке, используй Id как ключ идемпотентности.
➡️ C# Ready | #практика