Assuming you have two streams, a Stream csvStream
for the CSV file to be read and a Stream jsonStream
for the JSON file to be written, you can stream from CSV to JSON by combining Microsoft's TextFieldParser
with Json.NET's JsonTextWriter
like so:
public static partial class JsonExtensions
{
const int buffersize = 4096;
static readonly UTF8Encoding defaultEncoding = new UTF8Encoding(false, true);
public static void CopyCSVToJson(Stream csvStream, Stream jsonStream, Formatting formatting = Formatting.Indented, Encoding encoding = default)
{
encoding = encoding ?? defaultEncoding;
using (var textReader = new StreamReader(csvStream, encoding, true, buffersize, true))
using (var textWriter = new StreamWriter(jsonStream, encoding, buffersize, true))
CopyCSVToJson(textReader, textWriter, formatting);
}
public static void CopyCSVToJson(TextReader csvTextReader, TextWriter jsonTextWriter, Formatting formatting = Formatting.Indented)
{
using (var parser = new TextFieldParser(csvTextReader) { Delimiters = new[] { "," } })
{
if (parser.EndOfData)
return;
var headers = parser.ReadFields();
using (var jsonWriter = new JsonTextWriter(jsonTextWriter) { Formatting = formatting })
{
jsonWriter.WriteStartArray();
while (!parser.EndOfData)
{
var fields = parser.ReadFields();
jsonWriter.WriteStartObject();
foreach (var (name, value) in headers.Zip(fields))
{
jsonWriter.WritePropertyName(name);
// Check if the value is an integer, a decimal, or a Boolean.
// Could add BigInteger if needed
if (long.TryParse(value, out var l))
jsonWriter.WriteValue(l);
else if (decimal.TryParse(value, out var d))
jsonWriter.WriteValue(d);
else if (bool.TryParse(value, out var b))
jsonWriter.WriteValue(b);
else
jsonWriter.WriteValue(value);
}
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
}
}
}
And then you can call the routine above e.g. as follows:
using (var csvStream = File.OpenRead(csvFileName))
using (var jsonStream = File.OpenWrite(jsonFileName))
{
JsonExtensions.CopyCSVToJson(csvStream, jsonStream);
}
TextFieldParser
lives in the Microsoft.VisualBasic.FileIO
namespace of Microsoft.VisualBasic.Core.dll
and Microsoft.VisualBasic.dll
. It is perfectly usable from c#.
The copy method assumes the first row corresponds to the property names (as is shown in your question), and attempts to parse each cell as an integer, decimal or Boolean before writing the cell's value as a string.
The copy method assumes both streams have the same encoding. You could obviously generalize that if required.
Demo fiddle here.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…