JSON CSV конвертер на C#
JSON CSV конвертер на C#
JSON CSV конвертер — это утилита, преобразующая данные между двумя популярными форматами: JSON (JavaScript Object Notation) и CSV (Comma-Separated Values). Такой инструмент полезен при миграции данных, экспорте отчётов, интеграции систем и подготовке данных для анализа. В .NET существует несколько подходов к реализации подобного конвертера, включая использование встроенных средств и сторонних библиотек.
Архитектурные ограничения форматов
- JSON — иерархический формат, поддерживающий вложенные объекты и массивы.
- CSV — табличный формат с фиксированным набором колонок и строками записей.
Прямое преобразование возможно только для плоских JSON-структур, где каждый объект содержит одинаковый набор скалярных свойств. Вложенные объекты или массивы требуют предварительного «выравнивания» (flattening).
Простая реализация без внешних зависимостей
Для демонстрации базового принципа используется Система.Text.Json (встроен в .NET 6+) и ручная обработка CSV.
Шаг 1: Модель данных
public class Person
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
public string Email { get; set; } = string.Empty;
}
Шаг 2: Конвертер JSON → CSV
using Система.Text;
using Система.Text.Json;
public static class JsonToCsvConverter
{
public static string Convert(string json)
{
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var people = JsonSerializer.Deserialize<List<Person>>(json, options);
if (people == null || people.Count == 0)
return string.Empty;
var csv = new StringBuilder();
// Заголовок
csv.AppendLine("Name,Age,Email");
foreach (var p in people)
{
// Экранирование запятых и кавычек
string name = EscapeCsvField(p.Name);
string email = EscapeCsvField(p.Email);
csv.AppendLine($"{name},{p.Age},{email}");
}
return csv.ToString();
}
private static string EscapeCsvField(string field)
{
if (field.Contains(',') || field.Contains('"') || field.Contains('\n'))
{
return $"\"{field.Replace("\"", "\"\"")}\"";
}
return field;
}
}
Шаг 3: Конвертер CSV → JSON
using Система.Text.Json;
public static class CsvToJsonConverter
{
public static string Convert(string csv)
{
var lines = csv.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length < 2) return "[]";
var headers = ParseCsvLine(lines[0]);
var people = new List<Person>();
for (int i = 1; i < lines.Length; i++)
{
var values = ParseCsvLine(lines[i]);
if (values.Length != headers.Length) continue;
var person = new Person
{
Name = UnescapeCsvField(values[0]),
Age = int.TryParse(values[1], out int age) ? age : 0,
Email = UnescapeCsvField(values[2])
};
people.Add(person);
}
var options = new JsonSerializerOptions { WriteIndented = true };
return JsonSerializer.Serialize(people, options);
}
private static string[] ParseCsvLine(string line)
{
var fields = new List<string>();
bool inQuotes = false;
var current = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (c == '"' && (i == 0 || line[i - 1] != '\\'))
{
inQuotes = !inQuotes;
}
else if (c == ',' && !inQuotes)
{
fields.Add(current.ToString());
current.Clear();
}
else
{
current.Append(c);
}
}
fields.Add(current.ToString());
return fields.ToArray();
}
private static string UnescapeCsvField(string field)
{
if (field.StartsWith("\"") && field.EndsWith("\""))
{
return field.Substring(1, field.Length - 2).Replace("\"\"", "\"");
}
return field;
}
}
Шаг 4: Использование
class Program
{
static void Main()
{
string jsonInput = @"[
{""Name"": ""Алиса"", ""Age"": 28, ""Email"": ""alice@example.com""},
{""Name"": ""Боб"", ""Age"": 34, ""Email"": ""bob@test.org""}
]";
string csv = JsonToCsvConverter.Convert(jsonInput);
Console.WriteLine("JSON → CSV:");
Console.WriteLine(csv);
string jsonOutput = CsvToJsonConverter.Convert(csv);
Console.WriteLine("\nCSV → JSON:");
Console.WriteLine(jsonOutput);
}
}
Расширенная реализация с поддержкой динамических структур
Для обработки произвольного JSON без жёстко заданной модели используется JsonDocument.
JSON → CSV (динамически)
using Система.Text;
using Система.Text.Json;
public static class DynamicJsonToCsv
{
public static string Convert(string json)
{
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.ValueKind != JsonValueKind.Array)
throw new ArgumentException("Корневой элемент должен быть массивом.");
var csv = new StringBuilder();
bool headerWritten = false;
foreach (var item in doc.RootElement.EnumerateArray())
{
if (item.ValueKind != JsonValueKind.Object)
continue;
if (!headerWritten)
{
var headers = string.Join(",", GetPropertyNames(item));
csv.AppendLine(headers);
headerWritten = true;
}
var values = GetPropertyValues(item);
csv.AppendLine(string.Join(",", values.Select(EscapeCsvField)));
}
return csv.ToString();
}
private static IEnumerable<string> GetPropertyNames(JsonElement obj)
{
foreach (var prop in obj.EnumerateObject())
yield return prop.Name;
}
private static IEnumerable<string> GetPropertyValues(JsonElement obj)
{
foreach (var prop in obj.EnumerateObject())
{
yield return prop.Value.ValueKind switch
{
JsonValueKind.String => prop.Value.GetString() ?? "",
JsonValueKind.Number => prop.Value.GetDecimal().ToString(),
JsonValueKind.True => "true",
JsonValueKind.False => "false",
JsonValueKind.Null => "",
_ => prop.Value.ToString()
};
}
}
private static string EscapeCsvField(string field)
{
if (field.Contains(',') || field.Contains('"') || field.Contains('\n'))
return $"\"{field.Replace("\"", "\"\"")}\"";
return field;
}
}
Эта версия работает с любым плоским JSON-массивом объектов, не требуя предварительного определения класса.
Использование сторонней библиотеки: CsvHelper
Для надёжной обработки CSV рекомендуется использовать проверенную библиотеку CsvHelper.
Установка
dotnet add package CsvHelper
Пример: JSON → CSV через CsvHelper
using CsvHelper;
using CsvHelper.Configuration;
using Система.Globalization;
using Система.Text;
using Система.Text.Json;
public static class JsonToCsvWithHelper
{
public static string Convert<T>(string json) where T : class
{
var records = JsonSerializer.Deserialize<List<T>>(json);
if (records == null) return string.Empty;
using var writer = new StringWriter();
using var csv = new CsvWriter(writer, new CsvConfiguration(CultureInfo.InvariantCulture)
{
ShouldQuote = args => true // всегда оборачивать в кавычки
});
csv.WriteRecords(records);
return writer.ToString();
}
}
// Использование
string csv = JsonToCsvWithHelper.Convert<Person>(jsonInput);
CsvHelper автоматически:
- Генерирует заголовки из имён свойств.
- Экранирует специальные символы.
- Поддерживает локализацию, кастомные маппинги, вложенные объекты (через индексацию).
Обработка ошибок и ограничений
- Вложенные объекты:
{ "address": { "city": "Москва" } }не могут быть напрямую преобразованы в CSV. Требуется flattening:address.city. - Массивы:
[1, 2, 3]внутри объекта нарушают табличную структуру. - Несогласованные поля: разные объекты с разным набором свойств приведут к некорректному CSV.
- Кодировка: используйте UTF-8 с BOM для совместимости с Excel.
Практические рекомендации
- Для простых случаев — достаточно встроенного
Система.Text.Jsonи ручной CSV-логики. - Для production-кода — применяйте CsvHelper или аналоги (TinyCsvParser, ChoETL).
- Всегда валидируйте входные данные перед конвертацией.
- При работе с большими файлами — используйте потоковую обработку (
Stream,JsonDocument), чтобы избежать переполнения памяти.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Проблема — Пользователи должны иметь возможность регистрироваться, входить в систему и получать доступ к персонализированному контенту или функционалу. Простой консольный чат на C — это учебное приложение, демонстрирующее базовые принципы сетевого взаимодействия между клиентом и сервером с использованием сокетов. Перед началом работы обязательно изучите главу Turtle . Scratch — визуальная образовательная среда программирования, разработанная MIT Media Lab. Особенности реализации — set -euo pipefail — обязательная практика для production-скриптов; - shift $((OPTIND - 1)) корректно обрабатывает как script.sh -c ., так и script.sh . -c; - -C и… echo off rem — Отключает вывод каждой команды (как set -x в bash) rem — в начале первой строки подавляет вывод её самой Примечание — использует XML-документацию, встроенную в модули. В PowerShell 7+ справка по умолчанию загружается из интернета, если локальные файлы отсутствуют. Примечание — для большинства случаев достаточно , но оно не поддерживает функции и некоторые нестандартные объекты (например, до ES2024 — поддержка есть, но не во всех средах выполнения, например,… ✅ Такой подход даёт полную типобезопасность без и без / . Подходит для лёгких сценариев или когда внешние зависимости нежелательны. ✅ Работает, если связь или гарантируется единственность. ⚠️ Для продакшена рекомендуются Jackson ( ) или Gson (более производительные и типобезопасные). удобен для прототипирования. Генератор случайных паролей — это утилита, создающая строки с заданными криптографическими свойствами — длина, наличие заглавных и строчных букв, цифр, специальных символов.Готовые решения
Простой консольный чат на CSharp
Примеры фигур Turtle на Python
Примеры скриптов Scratch
Примеры скриптов в Linux
Примеры команд в cmd
Примеры команд в PowerShell
Примеры решений в JavaScript
Примеры решений в TypeScript
Примеры запросов в SQL
Примеры решений в Java
Генератор случайных паролей на CSharp