C# 如何使用JSON.net作为流将JSON转换为BSON
我想做一个JSON文件到BSON文件的流式转换。考虑到C# 如何使用JSON.net作为流将JSON转换为BSON,c#,json,json.net,bson,C#,Json,Json.net,Bson,我想做一个JSON文件到BSON文件的流式转换。考虑到JsonTextReader和的方法,这可能吗 代码如下: using ( StreamReader textReader = File.OpenText(@"k:\\BrokeredMessage_Alarmhub-Infra-Prd-Sbn_08-06-2019 11-13-34.json" ) ) using ( JsonTextReader jsonTextReader = new JsonTextReader( textReader
JsonTextReader
和的方法,这可能吗
代码如下:
using ( StreamReader textReader = File.OpenText(@"k:\\BrokeredMessage_Alarmhub-Infra-Prd-Sbn_08-06-2019 11-13-34.json" ) )
using ( JsonTextReader jsonTextReader = new JsonTextReader( textReader ))
using ( FileStream oFileStream = new FileStream( @"k:\\output.bson", FileMode.CreateNew ) )
using ( BsonDataWriter datawriter = new BsonDataWriter (oFileStream) )
{
...
}
我不想反序列化JSON文件的全部内容,因为我想读取JSON文件并以最小的内存负载写入BSON文件。这可以通过使用流实现吗?继承自,因此您可以使用从JSON流复制到BSON流(反之亦然,使用):
注:
JToken
(或dynamic
)中,您将得到一个带有数字键的对象,而不是数组如果
BsonDataWriter
创建的令牌缓存超出了系统内存,则需要手动实现一种算法,将JsonReader
流式处理到BSON流,在完成后返回输出流以写出最终对象大小
例如,假设您的根JSON容器是一个JSON对象数组。然后,以下方法将增量序列化数组,然后在流中查找以写入总大小:
public static partial class BsonExtensions
{
public static void CopyJsonToBson(string inputPath, string outputPath, FileMode fileMode)
{
using ( var textReader = File.OpenText(inputPath) )
using ( var jsonReader = new JsonTextReader( textReader ))
using ( var oFileStream = new FileStream( outputPath, fileMode ) )
{
CopyJsonToBson(jsonReader, oFileStream);
}
}
public static void CopyJsonToBson(JsonReader jsonReader, Stream stream)
{
var rootTokenType = jsonReader.ReadToContentAndAssert().TokenType;
if (!stream.CanSeek || rootTokenType != JsonToken.StartArray)
{
using ( var dataWriter = new BsonDataWriter(stream) { CloseOutput = false } )
{
dataWriter.WriteToken(jsonReader, stream.CanSeek);
}
}
else
{
stream.Flush(); // Just in case.
var initialPosition = stream.Position;
var buffer = new byte[256];
WriteInt(stream, 0, buffer); // CALCULATED SIZE TO BE CALCULATED LATER.
ulong index = 0;
while (jsonReader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
{
var bsonType = GetBsonType(jsonReader.TokenType, jsonReader.ValueType);
stream.WriteByte(unchecked((byte)bsonType));
WriteString(stream, index.ToString(NumberFormatInfo.InvariantInfo), buffer);
using (var dataWriter = new BsonDataWriter(stream) { CloseOutput = false })
{
dataWriter.WriteToken(jsonReader);
}
index++;
}
stream.WriteByte((byte)0);
stream.Flush();
var finalPosition = stream.Position;
stream.Position = initialPosition;
var size = checked((int)(finalPosition - initialPosition));
WriteInt(stream, size, buffer); // CALCULATED SIZE TO BE CALCULATED LATER.
stream.Position = finalPosition;
}
}
private static readonly Encoding Encoding = new UTF8Encoding(false);
private static void WriteString(Stream stream, string s, byte[] buffer)
{
if (s != null)
{
if (s.Length < buffer.Length / Encoding.GetMaxByteCount(1))
{
var byteCount = Encoding.GetBytes(s, 0, s.Length, buffer, 0);
stream.Write(buffer, 0, byteCount);
}
else
{
byte[] bytes = Encoding.GetBytes(s);
stream.Write(bytes, 0, bytes.Length);
}
}
stream.WriteByte((byte)0);
}
private static void WriteInt(Stream stream, int value, byte[] buffer)
{
unchecked
{
buffer[0] = (byte) value;
buffer[1] = (byte) (value >> 8);
buffer[2] = (byte) (value >> 16);
buffer[3] = (byte) (value >> 24);
}
stream.Write(buffer, 0, 4);
}
private static BsonType GetBsonType(JsonToken jsonType, Type valueType)
{
switch (jsonType)
{
case JsonToken.StartArray:
return BsonType.Array;
case JsonToken.StartObject:
return BsonType.Object;
case JsonToken.Null:
return BsonType.Null;
// Add primitives as required.
default:
throw new JsonWriterException(string.Format("BsonType for {0} not implemented.", jsonType));
}
}
//Copied from: https://github.com/JamesNK/Newtonsoft.Json.Bson/blob/master/Src/Newtonsoft.Json.Bson/BsonType.cs
//Original source: http://bsonspec.org/spec.html
enum BsonType : sbyte
{
Number = 1,
String = 2,
Object = 3,
Array = 4,
Binary = 5,
Undefined = 6,
Oid = 7,
Boolean = 8,
Date = 9,
Null = 10,
Regex = 11,
Reference = 12,
Code = 13,
Symbol = 14,
CodeWScope = 15,
Integer = 16,
TimeStamp = 17,
Long = 18,
MinKey = -1,
MaxKey = 127
}
}
public static partial class JsonExtensions
{
public static JsonReader ReadToContentAndAssert(this JsonReader reader)
{
return reader.ReadAndAssert().MoveToContentAndAssert();
}
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
注:
文档规范来扩展到流式JSON对象,也可以通过增强BsonExtensions.GetBsonType()
并对其进行适当的格式化来扩展到处理基元值
BsonDataWriter
)
但是,这样做可能会在输出流中导致大量的寻道,这可能会极大地影响性能JToken
(或dynamic
)中,您将得到一个带有数字键的对象,而不是数组如果
BsonDataWriter
创建的令牌缓存超出了系统内存,则需要手动实现一种算法,将JsonReader
流式处理到BSON流,在完成后返回输出流以写出最终对象大小
例如,假设您的根JSON容器是一个JSON对象数组。然后,以下方法将增量序列化数组,然后在流中查找以写入总大小:
public static partial class BsonExtensions
{
public static void CopyJsonToBson(string inputPath, string outputPath, FileMode fileMode)
{
using ( var textReader = File.OpenText(inputPath) )
using ( var jsonReader = new JsonTextReader( textReader ))
using ( var oFileStream = new FileStream( outputPath, fileMode ) )
{
CopyJsonToBson(jsonReader, oFileStream);
}
}
public static void CopyJsonToBson(JsonReader jsonReader, Stream stream)
{
var rootTokenType = jsonReader.ReadToContentAndAssert().TokenType;
if (!stream.CanSeek || rootTokenType != JsonToken.StartArray)
{
using ( var dataWriter = new BsonDataWriter(stream) { CloseOutput = false } )
{
dataWriter.WriteToken(jsonReader, stream.CanSeek);
}
}
else
{
stream.Flush(); // Just in case.
var initialPosition = stream.Position;
var buffer = new byte[256];
WriteInt(stream, 0, buffer); // CALCULATED SIZE TO BE CALCULATED LATER.
ulong index = 0;
while (jsonReader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
{
var bsonType = GetBsonType(jsonReader.TokenType, jsonReader.ValueType);
stream.WriteByte(unchecked((byte)bsonType));
WriteString(stream, index.ToString(NumberFormatInfo.InvariantInfo), buffer);
using (var dataWriter = new BsonDataWriter(stream) { CloseOutput = false })
{
dataWriter.WriteToken(jsonReader);
}
index++;
}
stream.WriteByte((byte)0);
stream.Flush();
var finalPosition = stream.Position;
stream.Position = initialPosition;
var size = checked((int)(finalPosition - initialPosition));
WriteInt(stream, size, buffer); // CALCULATED SIZE TO BE CALCULATED LATER.
stream.Position = finalPosition;
}
}
private static readonly Encoding Encoding = new UTF8Encoding(false);
private static void WriteString(Stream stream, string s, byte[] buffer)
{
if (s != null)
{
if (s.Length < buffer.Length / Encoding.GetMaxByteCount(1))
{
var byteCount = Encoding.GetBytes(s, 0, s.Length, buffer, 0);
stream.Write(buffer, 0, byteCount);
}
else
{
byte[] bytes = Encoding.GetBytes(s);
stream.Write(bytes, 0, bytes.Length);
}
}
stream.WriteByte((byte)0);
}
private static void WriteInt(Stream stream, int value, byte[] buffer)
{
unchecked
{
buffer[0] = (byte) value;
buffer[1] = (byte) (value >> 8);
buffer[2] = (byte) (value >> 16);
buffer[3] = (byte) (value >> 24);
}
stream.Write(buffer, 0, 4);
}
private static BsonType GetBsonType(JsonToken jsonType, Type valueType)
{
switch (jsonType)
{
case JsonToken.StartArray:
return BsonType.Array;
case JsonToken.StartObject:
return BsonType.Object;
case JsonToken.Null:
return BsonType.Null;
// Add primitives as required.
default:
throw new JsonWriterException(string.Format("BsonType for {0} not implemented.", jsonType));
}
}
//Copied from: https://github.com/JamesNK/Newtonsoft.Json.Bson/blob/master/Src/Newtonsoft.Json.Bson/BsonType.cs
//Original source: http://bsonspec.org/spec.html
enum BsonType : sbyte
{
Number = 1,
String = 2,
Object = 3,
Array = 4,
Binary = 5,
Undefined = 6,
Oid = 7,
Boolean = 8,
Date = 9,
Null = 10,
Regex = 11,
Reference = 12,
Code = 13,
Symbol = 14,
CodeWScope = 15,
Integer = 16,
TimeStamp = 17,
Long = 18,
MinKey = -1,
MaxKey = 127
}
}
public static partial class JsonExtensions
{
public static JsonReader ReadToContentAndAssert(this JsonReader reader)
{
return reader.ReadAndAssert().MoveToContentAndAssert();
}
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
注:
文档规范来扩展到流式JSON对象,也可以通过增强BsonExtensions.GetBsonType()
并对其进行适当的格式化来扩展到处理基元值
BsonDataWriter
)
然而,这样做可能会在输出流中导致大量的寻道,这可能会极大地影响每一次寻道
var inputPath = @"k:\\BrokeredMessage_Alarmhub-Infra-Prd-Sbn_08-06-2019 11-13-34.json";
var outputPath = @"k:\\output.bson";
BsonExtensions.CopyJsonToBson(inputPath, outputPath, FileMode.Create);