Json.NET可以将流序列化/反序列化到流/从流反序列化吗?

uqdfh47h  于 2023-08-08  发布在  .NET
关注(0)|答案(7)|浏览(172)

我听说Json.NET比DataContractJsonSerializer快,想给予看...
但是我在JsonConvert上找不到任何接受流而不是字符串的方法。
例如,为了在WinPhone上反序列化包含JSON的文件,我使用以下代码将文件内容读入字符串,然后反序列化为JSON。在我的(非常特别的)测试中,它似乎比使用DataContractJsonSerializer直接从流反序列化慢4倍……

  1. // DCJS
  2. DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(Constants));
  3. Constants constants = (Constants)dc.ReadObject(stream);
  4. // JSON.NET
  5. string json = new StreamReader(stream).ReadToEnd();
  6. Constants constants = JsonConvert.DeserializeObject<Constants>(json);

字符串
我做错了吗?

332nm8kg

332nm8kg1#

当前版本的Json.net不允许您使用接受的答案代码。当前的替代方案是:

  1. public static object DeserializeFromStream(Stream stream)
  2. {
  3. var serializer = new JsonSerializer();
  4. using (var sr = new StreamReader(stream))
  5. using (var jsonTextReader = new JsonTextReader(sr))
  6. {
  7. return serializer.Deserialize(jsonTextReader);
  8. }
  9. }

字符串
文件:Deserialize JSON from a file stream

zz2j4svz

zz2j4svz2#

  1. public static void Serialize(object value, Stream s)
  2. {
  3. using (StreamWriter writer = new StreamWriter(s))
  4. using (JsonTextWriter jsonWriter = new JsonTextWriter(writer))
  5. {
  6. JsonSerializer ser = new JsonSerializer();
  7. ser.Serialize(jsonWriter, value);
  8. jsonWriter.Flush();
  9. }
  10. }
  11. public static T Deserialize<T>(Stream s)
  12. {
  13. using (StreamReader reader = new StreamReader(s))
  14. using (JsonTextReader jsonReader = new JsonTextReader(reader))
  15. {
  16. JsonSerializer ser = new JsonSerializer();
  17. return ser.Deserialize<T>(jsonReader);
  18. }
  19. }

字符串

展开查看全部
f4t66c6m

f4t66c6m3#

**更新:**在当前版本中不再有效,正确答案见below无需投票否决,在旧版本中正确)。

JsonTextReader类与StreamReader一起使用,或者使用直接接受StreamReaderJsonSerializer重载:

  1. var serializer = new JsonSerializer();
  2. serializer.Deserialize(streamReader);

字符串

blmhpbnm

blmhpbnm4#

我写了一个扩展类来帮助我从JSON源(字符串、流、文件)反序列化。

  1. public static class JsonHelpers
  2. {
  3. public static T CreateFromJsonStream<T>(this Stream stream)
  4. {
  5. JsonSerializer serializer = new JsonSerializer();
  6. T data;
  7. using (StreamReader streamReader = new StreamReader(stream))
  8. {
  9. data = (T)serializer.Deserialize(streamReader, typeof(T));
  10. }
  11. return data;
  12. }
  13. public static T CreateFromJsonString<T>(this String json)
  14. {
  15. T data;
  16. using (MemoryStream stream = new MemoryStream(System.Text.Encoding.Default.GetBytes(json)))
  17. {
  18. data = CreateFromJsonStream<T>(stream);
  19. }
  20. return data;
  21. }
  22. public static T CreateFromJsonFile<T>(this String fileName)
  23. {
  24. T data;
  25. using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
  26. {
  27. data = CreateFromJsonStream<T>(fileStream);
  28. }
  29. return data;
  30. }
  31. }

字符串
现在反序列化就像写代码一样简单:

  1. MyType obj1 = aStream.CreateFromJsonStream<MyType>();
  2. MyType obj2 = "{\"key\":\"value\"}".CreateFromJsonString<MyType>();
  3. MyType obj3 = "data.json".CreateFromJsonFile<MyType>();


希望它能帮助别人。

展开查看全部
cczfrluj

cczfrluj5#

我在寻找一种方法来将一个开放的对象列表流到System.IO.Stream上,并从另一端读取它们,而无需在发送之前缓冲整个列表。(具体来说,我正在通过Web API从MongoDB流式传输持久化对象。
@Paul Tyng和@Rivers非常出色地回答了最初的问题,我用他们的答案为我的问题建立了一个概念证明。我决定在这里发布我的测试控制台应用程序,以防其他人也面临同样的问题。

  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.IO.Pipes;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Newtonsoft.Json;
  8. namespace TestJsonStream {
  9. class Program {
  10. static void Main(string[] args) {
  11. using(var writeStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.None)) {
  12. string pipeHandle = writeStream.GetClientHandleAsString();
  13. var writeTask = Task.Run(() => {
  14. using(var sw = new StreamWriter(writeStream))
  15. using(var writer = new JsonTextWriter(sw)) {
  16. var ser = new JsonSerializer();
  17. writer.WriteStartArray();
  18. for(int i = 0; i < 25; i++) {
  19. ser.Serialize(writer, new DataItem { Item = i });
  20. writer.Flush();
  21. Thread.Sleep(500);
  22. }
  23. writer.WriteEnd();
  24. writer.Flush();
  25. }
  26. });
  27. var readTask = Task.Run(() => {
  28. var sw = new Stopwatch();
  29. sw.Start();
  30. using(var readStream = new AnonymousPipeClientStream(pipeHandle))
  31. using(var sr = new StreamReader(readStream))
  32. using(var reader = new JsonTextReader(sr)) {
  33. var ser = new JsonSerializer();
  34. if(!reader.Read() || reader.TokenType != JsonToken.StartArray) {
  35. throw new Exception("Expected start of array");
  36. }
  37. while(reader.Read()) {
  38. if(reader.TokenType == JsonToken.EndArray) break;
  39. var item = ser.Deserialize<DataItem>(reader);
  40. Console.WriteLine("[{0}] Received item: {1}", sw.Elapsed, item);
  41. }
  42. }
  43. });
  44. Task.WaitAll(writeTask, readTask);
  45. writeStream.DisposeLocalCopyOfClientHandle();
  46. }
  47. }
  48. class DataItem {
  49. public int Item { get; set; }
  50. public override string ToString() {
  51. return string.Format("{{ Item = {0} }}", Item);
  52. }
  53. }
  54. }
  55. }

字符串
请注意,当AnonymousPipeServerStream被释放时,您可能会收到一个异常,我忽略了它,因为它与手头的问题无关。

展开查看全部
2guxujil

2guxujil6#

另一个选择是在Json中阅读,在JsonConvert类上使用DeserializeObject:

  1. using (StreamReader streamReader = new StreamReader("example.json"))
  2. {
  3. string json = streamReader.ReadToEnd();
  4. ObjectType object = JsonConvert.DeserializeObject<ObjectType>(json);
  5. }

字符串

p4tfgftt

p4tfgftt7#

当内存不足时,另一个方便的选择是定期刷新

  1. /// <summary>serialize the value in the stream.</summary>
  2. /// <typeparam name="T">the type to serialize</typeparam>
  3. /// <param name="stream">The stream.</param>
  4. /// <param name="value">The value.</param>
  5. /// <param name="settings">The json settings to use.</param>
  6. /// <param name="bufferSize"></param>
  7. /// <param name="leaveOpen"></param>
  8. public static void JsonSerialize<T>(this Stream stream,[DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings, int bufferSize=1024, bool leaveOpen=false)
  9. {
  10. using (var writer = new StreamWriter(stream,encoding: System.Text.Encoding.UTF32,bufferSize,leaveOpen))
  11. using (var jsonWriter = new JsonTextWriter(writer))
  12. {
  13. var ser = JsonSerializer.Create( settings );
  14. ser.Serialize(jsonWriter, value);
  15. jsonWriter.Flush();
  16. }
  17. }
  18. /// <summary>serialize the value in the stream asynchronously.</summary>
  19. /// <typeparam name="T"></typeparam>
  20. /// <param name="stream">The stream.</param>
  21. /// <param name="value">The value.</param>
  22. /// <param name="settings">The settings.</param>
  23. /// <param name="bufferSize">The buffer size, in bytes, set -1 to not flush till done</param>
  24. /// <param name="leaveOpen"> true to leave the stream open </param>
  25. /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
  26. public static Task JsonSerializeAsync<T>(this Stream stream,[DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings, int bufferSize=1024, bool leaveOpen=false, CancellationToken cancellationToken=default)
  27. {
  28. using (var writer = new StreamWriter(stream,encoding: System.Text.Encoding.UTF32,bufferSize: bufferSize,leaveOpen: leaveOpen))
  29. using (var jsonWriter = new JsonTextWriter(writer))
  30. {
  31. var ser = JsonSerializer.Create( settings );
  32. ser.Serialize(jsonWriter, value);
  33. return jsonWriter.Flush();
  34. }
  35. //jsonWriter.FlushAsnc with my version gives an error on the stream
  36. return Task.CompletedTask;
  37. }

字符串
你可以这样测试/使用它:

  1. [TestMethod()]
  2. public void WriteFileIntoJsonTest()
  3. {
  4. var file = new FileInfo(Path.GetTempFileName());
  5. try
  6. {
  7. var list = new HashSet<Guid>();
  8. for (int i = 0; i < 100; i++)
  9. {
  10. list.Add(Guid.NewGuid());
  11. }
  12. file.JsonSerialize(list);
  13. var sr = file.IsValidJson<List<Guid>>(out var result);
  14. Assert.IsTrue(sr);
  15. Assert.AreEqual<int>(list.Count, result.Count);
  16. foreach (var item in result)
  17. {
  18. Assert.IsFalse(list.Add(item), $"The GUID {item} should already exist in the hash set");
  19. }
  20. }
  21. finally
  22. {
  23. file.Refresh();
  24. file.Delete();
  25. }
  26. }


你需要创建扩展方法,这里是整个集合:

  1. public static class JsonStreamReaderExt
  2. {
  3. static JsonSerializerSettings _settings ;
  4. static JsonStreamReaderExt()
  5. {
  6. _settings = JsonConvert.DefaultSettings?.Invoke() ?? new JsonSerializerSettings();
  7. _settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
  8. _settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
  9. _settings.DateFormatHandling = DateFormatHandling.IsoDateFormat ;
  10. }
  11. /// <summary>
  12. /// serialize the value in the stream.
  13. /// </summary>
  14. /// <typeparam name="T"></typeparam>
  15. /// <param name="stream">The stream.</param>
  16. /// <param name="value">The value.</param>
  17. public static void JsonSerialize<T>(this Stream stream,[DisallowNull] T value)
  18. {
  19. stream.JsonSerialize(value,_settings);
  20. }
  21. /// <summary>
  22. /// serialize the value in the file .
  23. /// </summary>
  24. /// <typeparam name="T"></typeparam>
  25. /// <param name="file">The file.</param>
  26. /// <param name="value">The value.</param>
  27. public static void JsonSerialize<T>(this FileInfo file,[DisallowNull] T value)
  28. {
  29. if (string.IsNullOrEmpty(file.DirectoryName)==true && Directory.Exists(file.DirectoryName) == false)
  30. {
  31. Directory.CreateDirectory(file.FullName);
  32. }
  33. using var s = file.OpenWrite();
  34. s.JsonSerialize(value, _settings);
  35. file.Refresh();
  36. }
  37. /// <summary>
  38. /// serialize the value in the file .
  39. /// </summary>
  40. /// <typeparam name="T"></typeparam>
  41. /// <param name="file">The file.</param>
  42. /// <param name="value">The value.</param>
  43. /// <param name="settings">the json settings to use</param>
  44. public static void JsonSerialize<T>(this FileInfo file, [DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings)
  45. {
  46. if (string.IsNullOrEmpty(file.DirectoryName) == true && Directory.Exists(file.DirectoryName) == false)
  47. {
  48. Directory.CreateDirectory(file.FullName);
  49. }
  50. using var s = file.OpenWrite();
  51. s.JsonSerialize(value, settings);
  52. file.Refresh();
  53. }
  54. /// <summary>
  55. /// serialize the value in the file .
  56. /// </summary>
  57. /// <remarks>File will be refreshed to contain the new meta data</remarks>
  58. /// <typeparam name="T">the type to serialize</typeparam>
  59. /// <param name="file">The file.</param>
  60. /// <param name="value">The value.</param>
  61. /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
  62. public static async Task JsonSerializeAsync<T>(this FileInfo file, [DisallowNull] T value, CancellationToken cancellationToken = default)
  63. {
  64. if (string.IsNullOrEmpty(file.DirectoryName) == true && Directory.Exists(file.DirectoryName) == false)
  65. {
  66. Directory.CreateDirectory(file.FullName);
  67. }
  68. using (var stream = file.OpenWrite())
  69. {
  70. await stream.JsonSerializeAsync(value, _settings,bufferSize:1024,leaveOpen:false, cancellationToken).ConfigureAwait(false);
  71. }
  72. file.Refresh();
  73. }
  74. /// <summary>
  75. /// serialize the value in the file .
  76. /// </summary>
  77. /// <remarks>File will be refreshed to contain the new meta data</remarks>
  78. /// <typeparam name="T">the type to serialize</typeparam>
  79. /// <param name="file">The file to create or overwrite.</param>
  80. /// <param name="value">The value.</param>
  81. /// <param name="settings">the json settings to use</param>
  82. /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
  83. public static async Task JsonSerializeAsync<T>(this FileInfo file, [DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings, CancellationToken cancellationToken=default)
  84. {
  85. if (string.IsNullOrEmpty(file.DirectoryName) == true && Directory.Exists(file.DirectoryName) == false)
  86. {
  87. Directory.CreateDirectory(file.FullName);
  88. }
  89. using (var stream = file.OpenWrite())
  90. {
  91. await stream.JsonSerializeAsync(value, settings,bufferSize:1024,leaveOpen:false, cancellationToken).ConfigureAwait(false);
  92. }
  93. file.Refresh();
  94. }
  95. /// <summary>serialize the value in the stream.</summary>
  96. /// <typeparam name="T">the type to serialize</typeparam>
  97. /// <param name="stream">The stream.</param>
  98. /// <param name="value">The value.</param>
  99. /// <param name="settings">The json settings to use.</param>
  100. /// <param name="bufferSize">The buffer size, in bytes, set -1 to not flush till done</param>
  101. /// <param name="leaveOpen"> true to leave the stream open </param>
  102. public static void JsonSerialize<T>(this Stream stream,[DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings, int bufferSize=1024, bool leaveOpen=false)
  103. {
  104. using (var writer = new StreamWriter(stream,encoding: System.Text.Encoding.UTF32,bufferSize,leaveOpen))
  105. using (var jsonWriter = new JsonTextWriter(writer))
  106. {
  107. var ser = JsonSerializer.Create( settings );
  108. ser.Serialize(jsonWriter, value);
  109. jsonWriter.Flush();
  110. }
  111. }
  112. /// <summary>serialize the value in the stream asynchronously.</summary>
  113. /// <typeparam name="T"></typeparam>
  114. /// <param name="stream">The stream.</param>
  115. /// <param name="value">The value.</param>
  116. /// <param name="settings">The settings.</param>
  117. /// <param name="bufferSize">The buffer size, in bytes, set -1 to not flush till done</param>
  118. /// <param name="leaveOpen"> true to leave the stream open </param>
  119. /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
  120. public static Task JsonSerializeAsync<T>(this Stream stream,[DisallowNull] T value, [DisallowNull] JsonSerializerSettings settings, int bufferSize=1024, bool leaveOpen=false, CancellationToken cancellationToken=default)
  121. {
  122. using (var writer = new StreamWriter(stream,encoding: System.Text.Encoding.UTF32,bufferSize: bufferSize,leaveOpen: leaveOpen))
  123. using (var jsonWriter = new JsonTextWriter(writer))
  124. {
  125. var ser = JsonSerializer.Create( settings );
  126. ser.Serialize(jsonWriter, value);
  127. jsonWriter.Flush();
  128. }
  129. return Task.CompletedTask;
  130. }
  131. /// <summary>
  132. /// Determines whether [is valid json] [the specified result].
  133. /// </summary>
  134. /// <typeparam name="T"></typeparam>
  135. /// <param name="stream">The stream.</param>
  136. /// <param name="result">The result.</param>
  137. /// <returns><c>true</c> if [is valid json] [the specified result]; otherwise, <c>false</c>.</returns>
  138. public static bool IsValidJson<T>(this Stream stream, [NotNullWhen(true)] out T? result)
  139. {
  140. if (stream is null)
  141. {
  142. throw new ArgumentNullException(nameof(stream));
  143. }
  144. if (stream.Position != 0)
  145. {
  146. stream.Seek(0, SeekOrigin.Begin);
  147. }
  148. JsonSerializerSettings settings = (JsonConvert.DefaultSettings?.Invoke()) ?? new JsonSerializerSettings() { DateTimeZoneHandling = DateTimeZoneHandling.Utc, DateFormatHandling = DateFormatHandling.IsoDateFormat };
  149. settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
  150. using (var reader = new StreamReader(stream))
  151. using (var jsonReader = new JsonTextReader(reader))
  152. {
  153. var ser = JsonSerializer.Create(settings);
  154. try
  155. {
  156. result = ser.Deserialize<T>(jsonReader);
  157. }
  158. catch { result = default; }
  159. }
  160. return result is not null;
  161. }
  162. /// <summary>
  163. /// Determines whether [is valid json] [the specified settings].
  164. /// </summary>
  165. /// <typeparam name="T"></typeparam>
  166. /// <param name="stream">The stream.</param>
  167. /// <param name="settings">The settings.</param>
  168. /// <param name="result">The result.</param>
  169. /// <returns><c>true</c> if [is valid json] [the specified settings]; otherwise, <c>false</c>.</returns>
  170. public static bool IsValidJson<T>(this Stream stream, JsonSerializerSettings settings, [NotNullWhen(true)] out T? result)
  171. {
  172. if (stream is null)
  173. {
  174. throw new ArgumentNullException(nameof(stream));
  175. }
  176. if (settings is null)
  177. {
  178. throw new ArgumentNullException(nameof(settings));
  179. }
  180. if (stream.Position != 0)
  181. {
  182. stream.Seek(0, SeekOrigin.Begin);
  183. }
  184. using (var reader = new StreamReader(stream))
  185. using (var jsonReader = new JsonTextReader(reader))
  186. {
  187. var ser = JsonSerializer.Create(settings);
  188. try
  189. {
  190. result = ser.Deserialize<T>(jsonReader);
  191. }
  192. catch { result = default; }
  193. }
  194. return result is not null;
  195. }
  196. /// <summary>
  197. /// Determines whether file contains valid json using the specified settings and reads it into the output.
  198. /// </summary>
  199. /// <typeparam name="T">Type to convert into</typeparam>
  200. /// <param name="file">The file.</param>
  201. /// <param name="settings">The settings.</param>
  202. /// <param name="result">The result.</param>
  203. /// <returns><c>true</c> if [is valid json] [the specified settings]; otherwise, <c>false</c>.</returns>
  204. /// <exception cref="System.ArgumentNullException">file</exception>
  205. /// <exception cref="System.ArgumentNullException"></exception>
  206. /// <exception cref="System.ArgumentNullException">settings</exception>
  207. /// <exception cref="System.IO.FileNotFoundException">File could not be accessed</exception>
  208. public static bool IsValidJson<T>(this FileInfo file, JsonSerializerSettings settings, [NotNullWhen(true)] out T? result)
  209. {
  210. if (file is null)
  211. {
  212. throw new ArgumentNullException(nameof(file));
  213. }
  214. if (File.Exists(file.FullName) == false)
  215. {
  216. throw new FileNotFoundException("File could not be accessed",fileName: file.FullName);
  217. }
  218. using var stream = file.OpenRead();
  219. if (stream is null)
  220. {
  221. throw new ArgumentNullException(message:"Could not open the file and access the underlying file stream",paramName: nameof(file));
  222. }
  223. if (settings is null)
  224. {
  225. throw new ArgumentNullException(nameof(settings));
  226. }
  227. using (var reader = new StreamReader(stream))
  228. using (var jsonReader = new JsonTextReader(reader))
  229. {
  230. var ser = JsonSerializer.Create(settings);
  231. try
  232. {
  233. result = ser.Deserialize<T>(jsonReader);
  234. }
  235. catch { result = default; }
  236. }
  237. return result is not null;
  238. }
  239. /// <summary>
  240. /// Determines whether file contains valid json using the specified settings and reads it into the output.
  241. /// </summary>
  242. /// <typeparam name="T">Type to convert into</typeparam>
  243. /// <param name="file">The file.</param>
  244. /// <param name="result">The result.</param>
  245. /// <returns><c>true</c> if [is valid json] [the specified result]; otherwise, <c>false</c>.</returns>
  246. /// <exception cref="System.ArgumentNullException">file</exception>
  247. /// <exception cref="System.IO.FileNotFoundException">File could not be accessed</exception>
  248. public static bool IsValidJson<T>(this FileInfo file, [NotNullWhen(true)] out T? result)
  249. {
  250. if (file is null)
  251. {
  252. throw new ArgumentNullException(nameof(file));
  253. }
  254. if (File.Exists(file.FullName) == false)
  255. {
  256. throw new FileNotFoundException("File could not be accessed",fileName: file.FullName);
  257. }
  258. JsonSerializerSettings settings =( JsonConvert.DefaultSettings?.Invoke()) ?? new JsonSerializerSettings() { DateTimeZoneHandling= DateTimeZoneHandling.Utc, DateFormatHandling= DateFormatHandling.IsoDateFormat };
  259. settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
  260. return file.IsValidJson<T>(settings,out result);
  261. }
  262. }

展开查看全部

相关问题