किसी भी वस्तु को बाइट में बदलें []


138

मैं एक प्रोटोटाइप टीसीपी कनेक्शन लिख रहा हूं और मुझे भेजे जाने वाले डेटा को समरूप बनाने में कुछ परेशानी हो रही है।

फिलहाल, मैं स्ट्रिंग्स के अलावा कुछ नहीं भेज रहा हूं, लेकिन भविष्य में हम किसी भी ऑब्जेक्ट को भेजने में सक्षम होना चाहते हैं।

इस समय कोड काफी सरल है, क्योंकि मुझे लगा कि सब कुछ बाइट सरणी में डाला जा सकता है:

void SendData(object headerObject, object bodyObject)
{
  byte[] header = (byte[])headerObject;  //strings at runtime, 
  byte[] body = (byte[])bodyObject;      //invalid cast exception

  // Unable to cast object of type 'System.String' to type 'System.Byte[]'.
  ...
}

यह कोर्स आसानी से पर्याप्त हल है

if( state.headerObject is System.String ){...}

समस्या यह है, अगर मैं इसे इस तरह से करता हूं, तो मुझे किसी भी प्रकार की वस्तु की जांच करने की आवश्यकता होती है जिसे रनटाइम के दौरान बाइट में नहीं डाला जा सकता है।

चूँकि मैं हर उस वस्तु को नहीं जानता जो किसी बाइट में नहीं डाली जा सकती है [] रनटाइम पर, यह वास्तव में एक विकल्प नहीं है।

C # .NET 4.0 में किसी भी वस्तु को बाइट सरणी में कैसे परिवर्तित किया जाता है?


2
यह सामान्य रूप से किसी भी सार्थक तरीके से संभव नहीं है (उदाहरण के लिए, उदाहरण के लिए FileStream, या किसी भी ऑब्जेक्ट की तरह जो किसी हैंडल को इनकैप्सुलेट करता है)।
जेसन

2
क्या आप सभी क्लाइंट को .NET चलाने का इरादा रखते हैं? यदि उत्तर नहीं है, तो आपको सीरियलाइज़ेशन के कुछ अन्य रूप पर विचार करना चाहिए (XML, JSON, या लाइक)
R. Martinho Fernandes

जवाबों:


195

का प्रयोग करें BinaryFormatter:

byte[] ObjectToByteArray(object obj)
{
    if(obj == null)
        return null;
    BinaryFormatter bf = new BinaryFormatter();
    using (MemoryStream ms = new MemoryStream())
    {
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }
}

ध्यान दें कि objऔर किसी भी गुण / क्षेत्र के भीतर obj(और उनके सभी गुणों / क्षेत्रों के लिए इत्यादि) सभी को इस के साथ सफलतापूर्वक प्रसारित करने के लिए Serializableविशेषता के साथ टैग किए जाने की आवश्यकता होगी ।


13
दूसरी तरफ "किसी भी" ऑब्जेक्ट के साथ आप क्या करते हैं, इसके बारे में सावधान रहें, क्योंकि यह अब समझ में नहीं आ सकता है (उदाहरण के लिए, यदि वह ऑब्जेक्ट किसी फ़ाइल, या इसी तरह का एक हैंडल था)
रोलैंड शॉ

1
हाँ, सामान्य कैवेट लागू होते हैं, लेकिन उनमें से लोगों को याद दिलाने के लिए यह एक बुरा विचार नहीं है।
डैनियल डायपोलो

24
यह एक usingब्लॉक में मेमोरीस्ट्रीम के उपयोग को लपेटने के लिए अच्छा विचार हो सकता है , क्योंकि यह उत्सुकता से उपयोग किए गए आंतरिक बफर को जारी करेगा।
आर। मार्टिनो फर्नांडीस

1
क्या यह विधि .NET बाध्य है? क्या मैं StructLayoutAtrribute के साथ एक सी संरचना को अनुक्रमित कर सकता हूं और सॉकेट के माध्यम से सी कोड में भेज सकता हूं और उम्मीद करता हूं कि सी कोड संरचना को समझता है? मुझे नहीं लगता?
जो १

103

इस लेख को चेकआउट करें: http://www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-ice.html

नीचे दिए गए कोड का उपयोग करें

// Convert an object to a byte array
private byte[] ObjectToByteArray(Object obj)
{
    if(obj == null)
        return null;

    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();
    bf.Serialize(ms, obj);

    return ms.ToArray();
}

// Convert a byte array to an Object
private Object ByteArrayToObject(byte[] arrBytes)
{
    MemoryStream memStream = new MemoryStream();
    BinaryFormatter binForm = new BinaryFormatter();
    memStream.Write(arrBytes, 0, arrBytes.Length);
    memStream.Seek(0, SeekOrigin.Begin);
    Object obj = (Object) binForm.Deserialize(memStream);

    return obj;
}

10
जैसा कि इस उत्तर के लिए एक टिप्पणी में उल्लेख किया गया है , को MemorySteamएक usingब्लॉक में लपेटा जाना चाहिए ।
धोखेबाज़ 1024

क्या मुझे सम्मान में कुछ भी है? मैंने इसे इस तरह से लागू किया और 244 बाइट्स लॉन्ग बाइटअरे में 3 int32 पब्लिक मेंबर्स वाले ऑब्जेक्ट को फॉर्मेट करना। क्या मुझे C # सिंटैक्स के बारे में कुछ पता नहीं है या क्या ऐसा कुछ है जिसका मैं संभावित रूप से उपयोग नहीं कर पाऊंगा?
ढेन

क्षमा करें, मुझे आपकी समस्या नहीं मिल सकती। क्या आप कोड पोस्ट कर सकते हैं?
11

@kombsh मैं संक्षिप्त रूप में कोशिश करता हूं: [क्रमिक] वर्ग GameConfiguration {public map_options_t enumMapIndex; सार्वजनिक Int32 iPlayerAmount; निजी Int32 iGameID; } बाइट [] बाकपेट; GameConfiguration objGameConfClient = नया GameConfiguration (); baPacket = BinModler.ObjectToByteArray (objGameConfClient); अब baPacket में लगभग 244 बाइट्स f सामग्री है। मैं 12 की उम्मीद करता हूँ
dhein

1
@kombsh आप स्पष्ट रूप से अपने उदाहरण में डिस्पोजेबल वस्तुओं का निपटान कर सकते हैं।
रुडोल्फ ड्वोरसेक

30

जैसा कि दूसरों ने पहले कहा है, आप बाइनरी क्रमांकन का उपयोग कर सकते हैं, लेकिन यह एक अतिरिक्त बाइट्स का उत्पादन कर सकता है या एक ही डेटा के साथ ऑब्जेक्ट में deserialized हो सकता है। दूसरी ओर प्रतिबिंब का उपयोग करना काफी जटिल और बहुत धीमा है। एक और उपाय है जो आपकी वस्तुओं को बाइट्स और विसे-वर्सा में बदल सकता है - मार्शलिंग:

var size = Marshal.SizeOf(your_object);
// Both managed and unmanaged buffers required.
var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
// Copy object byte-to-byte to unmanaged memory.
Marshal.StructureToPtr(your_object, ptr, false);
// Copy data from unmanaged memory to managed buffer.
Marshal.Copy(ptr, bytes, 0, size);
// Release unmanaged memory.
Marshal.FreeHGlobal(ptr);

और बाइट्स को ऑब्जेक्ट में बदलने के लिए:

var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
var your_object = (YourType)Marshal.PtrToStructure(ptr, typeof(YourType));
Marshal.FreeHGlobal(ptr);

यह छोटी वस्तुओं और संरचनाओं के लिए इस दृष्टिकोण का उपयोग करने के लिए बहुत ही धीमा और आंशिक रूप से असुरक्षित है, क्षेत्र द्वारा अपने स्वयं के क्रमांकन क्षेत्र की तुलना में (अप्रबंधित स्मृति से दोहरी प्रतिलिपि के कारण), लेकिन यह क्रमांकन लागू किए बिना वस्तु को बाइट में बदलने के लिए सबसे आसान तरीका है] और बिना [सीरियल] विशेषता के।


1
आपको क्यों लगता है StructureToPtr+ Copyधीमा है? यह क्रमबद्धता की तुलना में धीमा कैसे हो सकता है? क्या कोई तेज उपाय है?
एंटोन सैमसनोव

यदि आप कुछ सरल प्रकारों से युक्त छोटी संरचनाओं के लिए इसका उपयोग करते हैं, तो हाँ (जो काफी सामान्य मामला है), यह मार्शलिंग और क्वाड कॉपीिंग (ऑब्जेक्ट से हीप में, हीप से बाइट्स तक, बाइट से हीप से, हीप से धीमा है) वस्तु के लिए)। यह तेजी से हो सकता है जब बाइट्स के बजाय IntPtr का उपयोग किया जाता है, लेकिन इस मामले में नहीं। और ऐसे प्रकारों के लिए तेजी से खुद के सीरियललाइज़र लिखना पड़ता है जो केवल बाइट सरणी में मान डालता है। मैं यह नहीं कह रहा हूं कि यह बिल्ड-इन सीरियललाइज़ेशन की तुलना में धीमा है और न ही यह "इतना बहुत धीमा है"।
अब्राहम

1
मुझे यह तरीका पसंद है क्योंकि यह बाइट-बाइट मैप करता है। C ++ मैपिंग के साथ मेमोरी एक्सचेंज करने के लिए यह वास्तव में एक अच्छा तरीका है। आपके लिए +1।
हाओ गुयेन

2
संभावित उपयोगकर्ताओं पर ध्यान दें, जबकि बहुत स्मार्ट है, यह उत्तर संरचना सरणियों पर काम नहीं करता है, जिन वस्तुओं को एक अप्रबंधित संरचना या वस्तुओं के रूप में चित्रित नहीं किया जा सकता है, जिनके पदानुक्रम में एक ComVanish (झूठा) माता-पिता हैं।
टर्नरी टापरी

1
यह बताने के लिए कि आपने "आकार" कैसे प्राप्त किया? मेंvar bytes = new byte[size];
रिकार्डो

13

आप जो देख रहे हैं वह क्रमबद्धता है। .Net प्लेटफ़ॉर्म के लिए सीरियलाइज़ेशन के कई रूप उपलब्ध हैं


10
public static class SerializerDeserializerExtensions
{
    public static byte[] Serializer(this object _object)
    {   
        byte[] bytes;
        using (var _MemoryStream = new MemoryStream())
        {
            IFormatter _BinaryFormatter = new BinaryFormatter();
            _BinaryFormatter.Serialize(_MemoryStream, _object);
            bytes = _MemoryStream.ToArray();
        }
        return bytes;
    }

    public static T Deserializer<T>(this byte[] _byteArray)
    {   
        T ReturnValue;
        using (var _MemoryStream = new MemoryStream(_byteArray))
        {
            IFormatter _BinaryFormatter = new BinaryFormatter();
            ReturnValue = (T)_BinaryFormatter.Deserialize(_MemoryStream);    
        }
        return ReturnValue;
    }
}

आप इसे नीचे दिए गए कोड की तरह उपयोग कर सकते हैं।

DataTable _DataTable = new DataTable();
_DataTable.Columns.Add(new DataColumn("Col1"));
_DataTable.Columns.Add(new DataColumn("Col2"));
_DataTable.Columns.Add(new DataColumn("Col3"));

for (int i = 0; i < 10; i++) {
    DataRow _DataRow = _DataTable.NewRow();
    _DataRow["Col1"] = (i + 1) + "Column 1";
    _DataRow["Col2"] = (i + 1) + "Column 2";
    _DataRow["Col3"] = (i + 1) + "Column 3";
    _DataTable.Rows.Add(_DataRow);
}

byte[] ByteArrayTest =  _DataTable.Serializer();
DataTable dt = ByteArrayTest.Deserializer<DataTable>();

6

उपयोग करने Encoding.UTF8.GetBytesसे उपयोग तेजी से होता है MemoryStream। यहां, मैं इनपुट ऑब्जेक्ट को JSON स्ट्रिंग में परिवर्तित करने के लिए NewtonsoftJson का उपयोग कर रहा हूं और फिर JSON स्ट्रिंग से बाइट्स प्राप्त कर रहा हूं ।

byte[] SerializeObject(object value) =>Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));

इस संस्करण के साथ @Daniel DiPaolo के संस्करण के लिए बेंचमार्क

Method                    |     Mean |     Error |    StdDev |   Median |  Gen 0 | Allocated |
--------------------------|----------|-----------|-----------|----------|--------|-----------| 
ObjectToByteArray         | 4.983 us | 0.1183 us | 0.2622 us | 4.887 us | 0.9460 |    3.9 KB |
ObjectToByteArrayWithJson | 1.548 us | 0.0309 us | 0.0690 us | 1.528 us | 0.3090 |   1.27 KB |

2

एक्सटेंशन्स क्लास में संयुक्त समाधान:

public static class Extensions {

    public static byte[] ToByteArray(this object obj) {
        var size = Marshal.SizeOf(data);
        var bytes = new byte[size];
        var ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(data, ptr, false);
        Marshal.Copy(ptr, bytes, 0, size);
        Marshal.FreeHGlobal(ptr);
        return bytes;
   }

    public static string Serialize(this object obj) {
        return JsonConvert.SerializeObject(obj);
   }

}

1

आप फ्रेमवर्क में अंतर्निहित क्रमांकन उपकरण का उपयोग कर सकते हैं और मेमोरीस्ट्रीम में अनुक्रमित कर सकते हैं । यह सबसे सरल विकल्प हो सकता है, लेकिन आपके परिदृश्य के लिए कड़ाई से आवश्यक हो सकता है की तुलना में एक बड़ा बाइट [] उत्पन्न कर सकता है।

यदि ऐसा है, तो आप प्रतिबिंब को खेतों और / या संपत्तियों पर पुनरावृत्त करने के लिए उपयोग कर सकते हैं जिन्हें क्रमबद्ध किया जाना है और मैन्युअल रूप से उन्हें मेमोरीस्ट्रीम में लिखना है, यदि गैर-तुच्छ प्रकारों को क्रमबद्ध करने के लिए आवश्यक हो तो क्रमबद्धता का आह्वान करना। यह विधि अधिक जटिल है और इसे लागू करने में अधिक समय लगेगा, लेकिन आप धारावाहिक धारा पर बहुत अधिक नियंत्रण कर सकते हैं।



1

मैं "बाइट्स में कास्टिंग" की तुलना में अभिव्यक्ति "क्रमांकन" का उपयोग करूंगा। किसी वस्तु को सीरियलाइज़ करने का अर्थ है उसे एक बाइट सरणी (या एक्सएमएल, या कुछ और) में परिवर्तित करना जिसका उपयोग दूरस्थ बॉक्स पर वस्तु को फिर से बनाने के लिए किया जा सकता है। .NET में, Serializableविशेषता उन प्रकारों को चिह्नित करती है जिनकी वस्तुओं को क्रमबद्ध किया जा सकता है।


1

ऑब्जेक्ट को बाइट सरणी में बदलने का वैकल्पिक तरीका:

TypeConverter objConverter = TypeDescriptor.GetConverter(objMsg.GetType());
byte[] data = (byte[])objConverter.ConvertTo(objMsg, typeof(byte[]));

इस की कोशिश की, यह मेरे लिए काम करने के बारे में नेट 4.6.1 और Windows 10 नहीं मालूम था
कंटंगा

0

एक अतिरिक्त कार्यान्वयन, जो न्यूटनसॉफ्ट.जॉन बाइनरी जेन्सन का उपयोग करता है और [क्रमिक] विशेषता के साथ सब कुछ चिह्नित करने की आवश्यकता नहीं होती है। केवल एक दोष यह है कि किसी वस्तु को अनाम वर्ग में लपेटना पड़ता है, इसलिए बाइनरी सीरियल के साथ प्राप्त बाइट सरणी इस से अलग हो सकती है।

public static byte[] ConvertToBytes(object obj)
{
    using (var ms = new MemoryStream())
    {
        using (var writer = new BsonWriter(ms))
        {
            var serializer = new JsonSerializer();
            serializer.Serialize(writer, new { Value = obj });
            return ms.ToArray();
        }
    }
}

अनाम वर्ग का उपयोग किया जाता है क्योंकि BSON एक वर्ग या सरणी से शुरू होना चाहिए। मैंने बाइट को डिसेर्बलाइज करने की कोशिश नहीं की है [] वापस वस्तु पर और यकीन नहीं है कि यह काम करता है, लेकिन बाइट में रूपांतरण की गति का परीक्षण किया है [और यह मेरी जरूरतों को पूरी तरह से संतुष्ट करता है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.