क्या Json.NET धारावाहिक / धारा से / के लिए deserialize कर सकता है?


151

मैंने सुना है कि Json.NET, DataContractJsonSerializer की तुलना में तेज़ है, और इसे आज़माना चाहता है ...

लेकिन मुझे JsonConvert पर ऐसा कोई तरीका नहीं मिला जो एक स्ट्रिंग के बजाय एक स्ट्रीम ले।

WinPhone पर JSON युक्त फ़ाइल को डिसेरलाइज़ करने के लिए, उदाहरण के लिए, मैं फ़ाइल कोड को एक स्ट्रिंग में पढ़ने के लिए निम्न कोड का उपयोग करता हूं, और फिर JSON में deserialize करता हूं। यह मेरे (बहुत तदर्थ) परीक्षण के बारे में प्रतीत होता है कि DataContractJsonSerializer का उपयोग करने की तुलना में परीक्षण करने के लिए सीधे धारा से deserialize ...

// DCJS
DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(Constants));
Constants constants = (Constants)dc.ReadObject(stream);

// JSON.NET
string json = new StreamReader(stream).ReadToEnd();
Constants constants = JsonConvert.DeserializeObject<Constants>(json);

क्या मैं गलत कर रहा हूँ?

जवाबों:


58

अद्यतन: यह वर्तमान संस्करण में काम नहीं करता है, सही उत्तर के लिए नीचे देखें ( नीचे वोट करने की आवश्यकता नहीं है, यह पुराने संस्करणों पर सही है )।

JsonTextReaderकक्षा का उपयोग करें StreamReaderया सीधे उपयोग करने वाले JsonSerializerअधिभार का उपयोग करें StreamReader:

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

23
बहुत यकीन है कि यह अब काम नहीं करता है। आपको एक JsonReader या TextReader
BradLaney

8
आप संस्करण संख्या को शामिल करना चाह सकते हैं यह अभी भी काम कर रहा है ताकि लोग जान सकें कि नीचे स्क्रॉल करना कब है।
पोहहा

@BradLaney युप JsonTextReader (दिया गया है। अब) जाने का रास्ता है
एंटोनी मेल्टज़ाइम

अपने जवाब को संपादित करने के लिए समय निकालने के लिए धन्यवाद, यह काम करने की स्थिति और उत्तर की सिफारिश है
निक बुल

281

Json.net का वर्तमान संस्करण आपको स्वीकृत उत्तर कोड का उपयोग करने की अनुमति नहीं देता है। एक वर्तमान विकल्प है:

public static object DeserializeFromStream(Stream stream)
{
    var serializer = new JsonSerializer();

    using (var sr = new StreamReader(stream))
    using (var jsonTextReader = new JsonTextReader(sr))
    {
        return serializer.Deserialize(jsonTextReader);
    }
}

प्रलेखन: एक फ़ाइल स्ट्रीम से JSON का वर्णन करें


4
JsonTextReader डिफ़ॉल्ट रूप से अपने StreamReader को बंद कर देगा, इसलिए JsonTextReader कंस्ट्रक्टर को कॉल में StreamReader का निर्माण करके इस उदाहरण को थोड़ा सरल बनाया जा सकता है।
ओलिवर बॉक

1
किसी भी विचार मैं इस कोड के साथ एक कस्टम कनवर्टर का उपयोग कैसे कर सकता हूं?
अनुक्रमक

1
वास्तव में, मेरे पास एक आउटऑफमेरी अपवाद है और मैं पहले से ही इस कोड का उपयोग करता हूं, बहुत सटीक रूप से। जो, मेरा मानना ​​है, यह कहना है कि यह कोई गारंटी नहीं है - अगर deserialized ऑब्जेक्ट काफी बड़ा है, और आप 32-बिट प्रक्रिया में फंस गए हैं, तो आपको इस कोड के साथ मेमोरी त्रुटियां भी मिल सकती हैं
PANDWood

1
मुझे एक त्रुटि मिल रही है "टाइप या नाम स्थान का नाम 'JsonTextReader' नहीं मिला" ... कोई सुझाव?
हनवसा

1
मुझे stream.Position = 0;अपने जसन को सही ढंग से जोड़ने के लिए जोड़ने की आवश्यकता थी ।
हाइब्रिड 2102

76
public static void Serialize(object value, Stream s)
{
    using (StreamWriter writer = new StreamWriter(s))
    using (JsonTextWriter jsonWriter = new JsonTextWriter(writer))
    {
        JsonSerializer ser = new JsonSerializer();
        ser.Serialize(jsonWriter, value);
        jsonWriter.Flush();
    }
}

public static T Deserialize<T>(Stream s)
{
    using (StreamReader reader = new StreamReader(s))
    using (JsonTextReader jsonReader = new JsonTextReader(reader))
    {
        JsonSerializer ser = new JsonSerializer();
        return ser.Deserialize<T>(jsonReader);
    }
}

2
धन्यवाद! इससे मुझे एक OutOfMemoryException से बचने में मदद मिली जो मुझे तब मिल रही थी जब मैं एक बहुत बड़े ऑब्जेक्ट संग्रह को एक स्ट्रिंग में धारावाहिक कर रहा था, और फिर उस स्ट्रिंग को अपनी स्ट्रीम में लिख रहा था (बजाय सीधे स्ट्रीम को धारावाहिक करने के)।
जॉन श्नाइडर

2
क्यों बहता है? उपयोग ब्लॉक के कारण होने वाली निपटान कॉल पहले से ही ऐसा नहीं करता है?
Şafak Gür

इसे कैसे उपयोग करे ?
सना

2
साइड नोट, क्योंकि यह दूसरों की मदद कर सकता है: यदि आप उपयोग JsonSerializer ser = JsonSerializer.Create(settings);करते हैं तो आप परिभाषित कर सकते हैं कि कौन सी सेटिंग्स का उपयोग डी / क्रमांकन के दौरान किया जा सकता है।
माइक

1
इस Serializeकार्यान्वयन के साथ एक संभावित मुद्दा यह है कि यह Streamपारित को एक तर्क के रूप में बंद कर देता है, जो आवेदन के आधार पर एक समस्या हो सकती है। .NET 4.5+ के साथ आप StreamWriterएक पैरामीटर के साथ एक निर्माण अधिभार का उपयोग करके इस समस्या से बच सकते हैं leaveOpenजो आपको स्ट्रीम को खुला छोड़ने देता है।
जो

29

मैंने JSON स्रोतों (स्ट्रिंग, स्ट्रीम, फ़ाइल) से deserializing में मदद करने के लिए एक विस्तार वर्ग लिखा है।

public static class JsonHelpers
{
    public static T CreateFromJsonStream<T>(this Stream stream)
    {
        JsonSerializer serializer = new JsonSerializer();
        T data;
        using (StreamReader streamReader = new StreamReader(stream))
        {
            data = (T)serializer.Deserialize(streamReader, typeof(T));
        }
        return data;
    }

    public static T CreateFromJsonString<T>(this String json)
    {
        T data;
        using (MemoryStream stream = new MemoryStream(System.Text.Encoding.Default.GetBytes(json)))
        {
            data = CreateFromJsonStream<T>(stream);
        }
        return data;
    }

    public static T CreateFromJsonFile<T>(this String fileName)
    {
        T data;
        using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
        {
            data = CreateFromJsonStream<T>(fileStream);
        }
        return data;
    }
}

वर्णन करना अब लिखना जितना आसान है:

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

आशा है कि यह किसी और की मदद करेगा।


2
इसके विरुद्ध : यह विस्तार विधियों के साथ सभी तारों को प्रदूषित करेगा। वर्कअराउंड्स : केवल यह घोषित करें कि Using SomeJsonHelpersNamespaceकहां जरूरत है या thisकीवर्ड को हटा दें और JsonHelpers.CreateFromJsonString(someJsonString) प्रो का उपयोग करें : यह उपयोग करने के लिए इतना आसान है :)
टोक '

1
यद्यपि इसे "प्रदूषणकारी" के रूप में देखा जा सकता है, स्ट्रिंग ऑब्जेक्ट में लगभग आधे एक्सटेंशन को उसी तरह से देखा जा सकता है। यह ऑब्जेक्ट को उस तरीके से बढ़ाता है, जो किसी के लिए उपयोगी होता है, जो लगातार स्ट्रिंग (json) से JSON तक बदल जाएगा।
विपश्यनास्सिन

इसके अलावा उपयोग Encoding.Defaultकरना बुरा है क्योंकि यह अलग-अलग मशीनों पर अलग-अलग व्यवहार करेगा (देखें Microsoft चेतावनी पर बड़ी चेतावनी)। JSON को UTF-8 होने की उम्मीद है और यही JsonSerializer को उम्मीद है। इस प्रकार यह होना चाहिए Encoding.UTF8। के रूप में कोड गैर-ASCII वर्णों का उपयोग किया जाता है, तो गारबेज स्ट्रिंग्स का उत्पादन होगा या deserialize करने में विफल रहेगा।
ckuri

17

मैं इस सवाल पर पहुंचा कि एक खुली हुई वस्तुओं की सूची को एक पर स्ट्रीम करने का एक तरीका खोज रहा था System.IO.Streamऔर भेजने से पहले पूरी सूची को बफर किए बिना उन्हें दूसरे छोर से पढ़ लिया। (विशेष रूप से मैं वेब एपीआई पर MongoDB से लगातार वस्तुओं को स्ट्रीमिंग कर रहा हूं।)

@Paul Tyng और @Rivers ने मूल प्रश्न का उत्तर देने के लिए एक उत्कृष्ट कार्य किया, और मैंने उनके उत्तरों का उपयोग अपनी समस्या के लिए अवधारणा का प्रमाण बनाने के लिए किया। मैंने अपना टेस्ट कंसोल ऐप यहां पोस्ट करने का फैसला किया, अगर किसी को भी इसी मुद्दे का सामना करना पड़ रहा है।

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace TestJsonStream {
    class Program {
        static void Main(string[] args) {
            using(var writeStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.None)) {
                string pipeHandle = writeStream.GetClientHandleAsString();
                var writeTask = Task.Run(() => {
                    using(var sw = new StreamWriter(writeStream))
                    using(var writer = new JsonTextWriter(sw)) {
                        var ser = new JsonSerializer();
                        writer.WriteStartArray();
                        for(int i = 0; i < 25; i++) {
                            ser.Serialize(writer, new DataItem { Item = i });
                            writer.Flush();
                            Thread.Sleep(500);
                        }
                        writer.WriteEnd();
                        writer.Flush();
                    }
                });
                var readTask = Task.Run(() => {
                    var sw = new Stopwatch();
                    sw.Start();
                    using(var readStream = new AnonymousPipeClientStream(pipeHandle))
                    using(var sr = new StreamReader(readStream))
                    using(var reader = new JsonTextReader(sr)) {
                        var ser = new JsonSerializer();
                        if(!reader.Read() || reader.TokenType != JsonToken.StartArray) {
                            throw new Exception("Expected start of array");
                        }
                        while(reader.Read()) {
                            if(reader.TokenType == JsonToken.EndArray) break;
                            var item = ser.Deserialize<DataItem>(reader);
                            Console.WriteLine("[{0}] Received item: {1}", sw.Elapsed, item);
                        }
                    }
                });
                Task.WaitAll(writeTask, readTask);
                writeStream.DisposeLocalCopyOfClientHandle();
            }
        }

        class DataItem {
            public int Item { get; set; }
            public override string ToString() {
                return string.Format("{{ Item = {0} }}", Item);
            }
        }
    }
}

ध्यान दें कि आप एक अपवाद प्राप्त कर सकते हैं जब AnonymousPipeServerStreamनिपटाया जाता है, तो मैंने इसे अनदेखा कर दिया क्योंकि यह हाथ में समस्या के लिए प्रासंगिक नहीं है।


1
मुझे इसे संशोधित करने की आवश्यकता है ताकि मुझे कोई संपूर्ण JSON ऑब्जेक्ट मिल सके। मेरा सर्वर और क्लाइंट JSON के स्निपेट्स भेजकर संवाद करते हैं ताकि क्लाइंट भेज सके {"sign in":{"username":"nick"}}{"buy item":{"_id":"32321123"}}और इसे JSON के दो टुकड़े के रूप में देखने की जरूरत है, जब यह एक टुकड़ा पढ़ता है तो हर बार किसी घटना को इंगित करता है। नोडज में यह कोड की 3 लाइनों में किया जा सकता है।
Nick Sotiros
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.