যে কোনও বস্তুকে একটি বাইটে রূপান্তর করুন []


138

আমি একটি প্রোটোটাইপ টিসিপি সংযোগ লিখছি এবং ডেটা প্রেরণের জন্য একত্রীকরণ করতে আমার কিছুটা সমস্যা হচ্ছে।

এই মুহুর্তে, আমি স্ট্রিং ব্যতীত আর কিছুই পাঠাচ্ছি না, তবে ভবিষ্যতে আমরা কোনও বস্তু পাঠাতে সক্ষম হতে চাই be

কোডটি এই মুহূর্তে বেশ সহজ, কারণ আমি ভেবেছিলাম যে সমস্ত কিছু বাইট অ্যারেতে ফেলে দেওয়া যেতে পারে:

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 ){...}

সমস্যাটি হ'ল, যদি আমি সেভাবে এটি করি তবে আমার প্রতিটি ধরণের অবজেক্টের জন্য যাচাই করা দরকার যা রানটাইমগুলিতে একটি বাইটে কাস্ট করা যায় না]

যেহেতু রানটাইমের সময় যে সমস্ত বস্তু বাইটে কাস্ট করা যায় না আমি জানি না, এটি সত্যই কোনও বিকল্প নয়।

কীভাবে কেউ সি #। নেট 4.0 এ বাইট অ্যারে রূপান্তর করতে পারে?


2
এটি সাধারণভাবে কোনও অর্থবহ উপায়ে সম্ভব নয় (উদাহরণস্বরূপ, একটি উদাহরণ হিসাবে বিবেচনা করুন FileStream, বা যে কোনও বস্তু যা এইরকম একটি হ্যান্ডেল সজ্জিত করে)।
জেসন

2
আপনার কি সমস্ত ক্লায়েন্ট .NET চলমান আছে? উত্তরটি যদি না হয় তবে আপনার সিরিয়ালাইজেশনের কিছু অন্য রূপ (এক্সএমএল, জেএসওএন বা পছন্দগুলি) বিবেচনা করা উচিত
আর মার্টিনহো ফার্নান্দিস

উত্তর:


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বৈশিষ্ট্যের সাথে ট্যাগ করা দরকার be


13
তোমার সমস্যা কি অন্য দিকে "কোনো" বস্তু না থেকে সতর্ক থাকুন, যেমন এটি আর ইন্দ্রিয় (উদাহরণস্বরূপ, যদি যে বস্তুর একটি ফাইলে একটি হ্যান্ডল ছিল, বা অনুরূপ) করতে পারে
রোল্যান্ড শ

1
হ্যাঁ, সাধারণ সতর্কতামূলক প্রয়োগ হয় তবে এগুলির লোকদের মনে করিয়ে দেওয়া কোনও খারাপ ধারণা নয়।
ড্যানিয়েল ডিপোলো

24
কোনও usingব্লকে মেমোরিস্ট্রিমের ব্যবহারটি মুড়িয়ে ফেলা ভাল ধারণা হতে পারে , কারণ এটি আগ্রহের সাথে ব্যবহৃত অভ্যন্তরীণ বাফারটি প্রকাশ করবে।
আর মার্টিনহো ফার্নান্দেস

1
এই পদ্ধতি। নেট আবদ্ধ? আমি কি স্ট্রাক্ট লেআউটআর্ট্রিবিউটের সাথে একটি সি স্ট্রাইকটি সিরিয়ালাইজ করতে পারি এবং সকেটের মাধ্যমে একটি সি কোডে প্রেরণ করতে পারি এবং আশা করি যে সি কোডটি স্ট্রাকটি বোঝে? আমি মনে করি না?
জো

103

এই নিবন্ধটি দেখুন: http://www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-vice.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ব্লকে আবৃত করা উচিত ।
rookie1024

অ্যাডিশনে আমাকে সম্মান করার মতো কিছু আছে কি? আমি সেভাবে এটি বাস্তবায়ন করেছি এবং 3 জন 32 জন সদস্যের সমন্বিত একটি অবজেক্টটি ফর্ম্যাট করার ফলে 244 বাইট দীর্ঘ লম্বা বাইটআরে ফলাফল হয়। আমি কি সি # সিনট্যাক্স সম্পর্কে কিছু জানছি না বা এমন কোনও কিছু আছে যা সম্ভবত আমি ব্যবহার করে মিস করব?
dhein

দুঃখিত, আমি আপনার সমস্যা পেতে পারি না। আপনি কোড পোস্ট করতে পারেন?
কুম্বস

@ কম্বশ আমি সংক্ষিপ্ত আকারে চেষ্টা করি: [সিরিয়ালাইজযোগ্য] শ্রেণি গেম কনফিগারেশন {পাবলিক ম্যাপ_পোশন_টি এনামম্যাপ ইনডেক্স; পাবলিক ইন্টার 32 আইপ্লেয়ারঅ্যামাউন্ট; বেসরকারী Int32 iGameID; } বাইট [] বাপ্যাকেট; গেমকনফিগারেশন @GameConfClient = নতুন গেম কনফিগারেশন (); baPacket = BinModler.ObjectToByteArray (@GameConfClient); এখন বাপ্যাকেটে প্রায় 244 বাইট এফ সামগ্রী রয়েছে। আমি প্রত্যাশিত 12.
dhein

1
@ কুম্বস আপনি নিজের উদাহরণে ডিসপোজেবল অবজেক্টগুলিকে স্পষ্টভাবে নিষ্পত্তি করতে পারেন।
রুডল্ফ ডিভোরেসেক

30

অন্যরা এর আগে যেমন বলেছে, আপনি বাইনারি সিরিয়ালাইজেশন ব্যবহার করতে পারেন তবে এটি অতিরিক্ত বাইট তৈরি করতে পারে বা একই ডেটা না করে কোনও বস্তুতে ডিসরিয়ালাইজড হতে পারে। অন্যদিকে প্রতিবিম্ব ব্যবহার করা বেশ জটিল এবং খুব ধীর। আরও একটি সমাধান রয়েছে যা আপনার অবজেক্টগুলিকে কঠোরভাবে বাইটে এবং ভাইস-বিপরীতে রূপান্তর করতে পারে - মার্শালিং:

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);

ক্ষুদ্রতর অবজেক্ট এবং ক্ষেত্রের মাধ্যমে নিজের ক্রমিক ক্ষেত্রের সাথে তুলনামূলকভাবে ছোট ছোট বস্তুগুলির জন্য এই পদ্ধতিটি ব্যবহার করা আংশিকভাবে অনিরাপদ (কারণ অবিকৃত স্মৃতি থেকে / ডাবল অনুলিপি করার কারণে) তবে সিরিয়ালাইজেশন প্রয়োগ না করে অবজেক্টকে বাইটে কঠোরভাবে রূপান্তর করা এর সহজতম উপায় way এবং [সিরিয়ালাইজযোগ্য] বৈশিষ্ট্য ছাড়াই।


1
আপনি কেন StructureToPtr+ Copyধীর বলে মনে করেন ? সিরিয়ালাইজেশনের চেয়ে ধীর হতে পারে কীভাবে? কোন দ্রুত সমাধান আছে?
আন্তন স্যামসনভ

আপনি যদি এটি কয়েকটি সাধারণ ধরণের সমন্বিত ছোট স্ট্রাক্টের জন্য ব্যবহার করেন তবে হ্যাঁ (যা বেশ সাধারণ ঘটনা), মার্শেলিং এবং কোয়াড কপি করার কারণে এটি ধীর হয় (বস্তু থেকে গাদা থেকে, গাদা থেকে বাইটে, বাইট থেকে হিপ পর্যন্ত) to আপত্তি)। এটি দ্রুততর হতে পারে যখন বাইটের পরিবর্তে ইন্টারপ্রেটার ব্যবহার করা হয়, তবে এই ক্ষেত্রে নয়। এবং এই জাতীয় ধরণের নিজস্ব সিরিয়ালাইজার লিখতে এটি দ্রুততর যা মানগুলি কেবল বাইট অ্যারেতে রাখে। আমি বলছি না এটি বিল্ড-ইন সিরিয়ালাইজেশনের চেয়ে ধীর এবং এটি "এত জঘন্য ধীর"।
আবেরো

1
আমি এই পদ্ধতিটি পছন্দ করি যেহেতু এটি বাই বাই বাই ম্যাপ করে। এটি সি ++ ম্যাপিংয়ের সাথে মেমরি বিনিময় করার জন্য একটি দুর্দান্ত পদ্ধতি। আপনার জন্য +1
হাও এনগুইন

2
সম্ভাব্য ব্যবহারকারীদের জন্য নোট করুন, খুব স্মার্ট হলেও, এই উত্তরটি কাঠামোর অ্যারেগুলিতে কাজ করে না, এমন অবজেক্টগুলি যা নিয়ন্ত্রণহীন কাঠামো হিসাবে মার্শাল করা যায় না বা যে পদার্থগুলির ক্রিয়াকলাপে কমভিজিবল (মিথ্যা) পিতামাতা থাকে।
টেরনারি টোপরিয়ার

1
আপনি "আকার" কীভাবে পেয়েছিলেন তা থেকে পেলাম? ইনvar bytes = new byte[size];
রিকার্ডো

13

আপনি যা খুঁজছেন তা সিরিয়ালাইজেশন। । নেট প্ল্যাটফর্মের জন্য বিভিন্ন ধরণের সিরিয়ালাইজেশন উপলব্ধ


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। এখানে, আমি নিউটনসফটজসনটি ইনপুট অবজেক্টটিকে জেএসএন স্ট্রিংয়ে রূপান্তর করতে এবং তারপরে জেএসএন স্ট্রিং থেকে বাইটস পেতে ব্যবহার করছি ।

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

এই সংস্করণটি সহ @ ডানিয়েল ডিপোলো'র সংস্করণটির জন্য বেঞ্চমার্ক

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 এবং উইন্ডোজ 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 এর কোনও ক্লাস বা অ্যারে দিয়ে শুরু করা উচিত। আমি বাইটটিকে ডিজেইরিয়াল করার চেষ্টা করি না [আবার] আপত্তি করতে এবং এটি নিশ্চিত কিনা তা কাজ করে কিনা, তবে বাইটে রূপান্তরকরণের গতি পরীক্ষা করে দেখেছি [] এবং এটি আমার প্রয়োজনীয়তা সম্পূর্ণরূপে পূরণ করে।


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.