কীভাবে একটি # বাইট অ্যারেতে কোন বস্তুকে রূপান্তর করবেন #


102

আমার কাছে বাইনারি ফাইলে লিখতে হবে এমন সামগ্রীর সংকলন রয়েছে।

কমপ্যাক্ট হওয়ার জন্য আমার ফাইলে থাকা বাইটগুলি দরকার, তাই আমি ব্যবহার করতে পারি না BinaryFormatter। BinaryFormatterdeserialization প্রয়োজনের জন্য সমস্ত ধরণের তথ্য ছুড়ে ফেলে।

আমি যদি চেষ্টা করি

byte[] myBytes = (byte[]) myObject 

আমি একটি রানটাইম ব্যতিক্রম পাই।

আমার এটি দ্রুত হওয়া দরকার তাই আমি চারপাশে বাইটের অ্যারেগুলি অনুলিপি করতাম না। আমি ঠিক কাস্ট byte[] myBytes = (byte[]) myObjectকাজ করতে চাই !

ঠিক আছে পরিষ্কার করার জন্য, আউটপুট ফাইলে আমার কোনও মেটাডেটা থাকতে পারে না । শুধু অবজেক্ট বাইট। বস্তু থেকে বস্তু প্যাক করা। প্রাপ্ত উত্তরগুলির ভিত্তিতে, দেখে মনে হচ্ছে আমি নিম্ন-স্তরের Buffer.BlockCopyকোডটি লিখছি । সম্ভবত অনিরাপদ কোড ব্যবহার করছে।

উত্তর:


180

কোনও বস্তুকে বাইট অ্যারেতে রূপান্তর করতে:

// Convert an object to a byte array
public static byte[] ObjectToByteArray(Object obj)
{
    BinaryFormatter bf = new BinaryFormatter();
    using (var ms = new MemoryStream())
    {
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }
}

আপনাকে কেবল এই কোডটি আপনার কোডটিতে অনুলিপি করতে হবে এবং এটিতে আপনাকে বাইট অ্যারেতে রূপান্তর করতে হবে এমন অবজেক্টটি প্রেরণ করতে হবে। আপনার যদি বাইট অ্যারে আবার কোনও জিনিসে রূপান্তর করতে হয় তবে আপনি নীচের ফাংশনটি ব্যবহার করতে পারেন:

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

আপনি কাস্টম ক্লাসের সাথে এই ফাংশনগুলি ব্যবহার করতে পারেন। [Serializable]সিরিয়ালাইজেশন সক্ষম করতে আপনার ক্লাসে কেবলমাত্র বৈশিষ্ট্য যুক্ত করতে হবে


9
আমি এটি চেষ্টা করেছিলাম এবং এতে সমস্ত ধরণের মেটাডেটা যুক্ত হয়েছে। ওপি জানিয়েছে যে তিনি মেটাটাটা চান না।
— ব্যবহারকারী316117

4
উল্লেখ করার মতো নয়, প্রত্যেকেই ধরে নিয়েছে যে আপনি যা সিরিয়ালিয়াল করার চেষ্টা করছেন সেটি এমন কিছু যা আপনি লিখেছেন বা ইতিমধ্যে সিরিয়ালায়িত হওয়ার জন্য সেট আপ করা হয়েছে।
— Hexum064

4
আপনি MemoryStreamদ্বিতীয় কোড উদাহরণের কন্ডাক্টরকে সরাসরি বাইট অ্যারে পাস করতে পারেন । এই ব্যবহারের নিষ্কাশন হবে Write(...)এবং Seek(...)।
— অজানা 6656

41

আপনি যদি সিরিয়ালযুক্ত ডেটাটি সত্যই কমপ্যাক্ট হতে চান তবে আপনি নিজে সিরিয়ালাইজেশন পদ্ধতিগুলি লিখতে পারেন। এইভাবে আপনার ন্যূনতম ওভারহেড থাকবে।

উদাহরণ:

public class MyClass {

   public int Id { get; set; }
   public string Name { get; set; }

   public byte[] Serialize() {
      using (MemoryStream m = new MemoryStream()) {
         using (BinaryWriter writer = new BinaryWriter(m)) {
            writer.Write(Id);
            writer.Write(Name);
         }
         return m.ToArray();
      }
   }

   public static MyClass Desserialize(byte[] data) {
      MyClass result = new MyClass();
      using (MemoryStream m = new MemoryStream(data)) {
         using (BinaryReader reader = new BinaryReader(m)) {
            result.Id = reader.ReadInt32();
            result.Name = reader.ReadString();
         }
      }
      return result;
   }

}

লেখার জন্য আমার কাছে বেশ কয়েকটি কীট এবং বিভিন্ন স্ট্রিং কী?
— স্মিথ

4
@ স্মিথ: হ্যাঁ, আপনি এটি করতে পারেন, কেবল একে অপরের পরে লিখুন। BinaryWriterএমন একটি বিন্যাসে তাদের লিখতে হবে BinaryReader, পড়তে পারেন যতদিন না পর্যন্ত আপনি লিখে একই আদেশ পড়া হিসাবে।
— গুফা 21'12

4
এ BinaryWriter/Readerএবং ব্যবহারের মধ্যে পার্থক্য কীBinaryFormatter
— স্মিথ

4
@ স্মিথ: BinaryWriter/Readerআপনি নিজেই সিরিয়ালাইজেশন / ডিসরিয়ালাইজেশন করেন এবং আপনি যতটা সম্ভব কমপ্যাক্ট কেবল সেই ডেটা লিখতে / পড়তে পারেন। BinaryFormatterব্যবহারসমূহ প্রতিফলন লেখ / পড়া কোন ডেটা জানতে, এবং একটি বিন্যাস ব্যবহার যে সব সম্ভব ক্ষেত্রে জন্য কাজ করে। এটি স্ট্রিমের ফর্ম্যাট সম্পর্কে মেটা তথ্যও অন্তর্ভুক্ত করে, যাতে এটি আরও বেশি ওভারহেড যুক্ত করে।
— গুফা 21

4
@ স্মিথ: আপনি এনামে কাস্ট করতে পারেন int(বা যদি আপনি এনামের জন্য স্টোরেজ হিসাবে অন্য কোনও ধরণের উল্লেখ করেছেন) এবং লিখতে পারেন। আপনি যখন এটি পড়েন আপনি এটি এনাম টাইপ করতে পারেন can
— গুফা

31

ওয়েল থেকে একটি ঢালাই myObjectকরার byte[]কখনোই কাজ করে যাচ্ছে, যদি না আপনি একটি সুনির্দিষ্ট রূপান্তর অথবা যদি পেয়েছেন করা হয় myObject হয় একটি byte[]। আপনার কোনও ধরণের সিরিয়ালাইজেশন কাঠামো দরকার । প্রোটোকল বাফার সহ প্রচুর পরিমাণে রয়েছে যা আমার কাছে এবং প্রিয়। স্থান এবং সময় উভয়ের ক্ষেত্রে এটি বেশ "পাতলা এবং গড়"।

আপনি দেখতে পাবেন যে প্রায় সমস্ত সিরিয়ালাইজেশন ফ্রেমওয়ার্কগুলিতে আপনি সিরিয়ালাইজ করতে পারবেন তার উপর উল্লেখযোগ্য বাধা রয়েছে - তবে ক্রস-প্ল্যাটফর্ম হওয়ার কারণে কিছু থেকে প্রোটোকল বাফারগুলি।

আপনি যদি আরও প্রয়োজনীয়তা দিতে পারেন তবে আমরা আপনাকে আরও সাহায্য করতে পারি - তবে এটি কাস্টিংয়ের মতো সহজ হবে না ...

সম্পাদনা: কেবল এই প্রতিক্রিয়া জানাতে:

অবজেক্টের বাইটগুলি ধারণ করতে আমার বাইনারি ফাইলটি দরকার। কেবল বাইটস, কোনও মেটাডেটা নেই। বস্তু থেকে বস্তু প্যাক করা। তাই আমি কাস্টম সিরিয়ালাইজেশন প্রয়োগ করব।

দয়া করে মনে রাখবেন যে আপনার অবজেক্টের বাইটগুলি প্রায়শই উল্লেখ করা হয় ... সুতরাং তাদের সাথে কী করা উচিত তা আপনার কাজ করা দরকার।

আমি সন্দেহ করি যে আপনি নিজের কাস্টম সিরিয়ালাইজেশন কাঠামোটি ডিজাইনিং এবং বাস্তবায়ন করেছেন তা আপনার কল্পনার চেয়ে শক্ত।

আমি ব্যক্তিগতভাবে সুপারিশ করব যে যদি আপনাকে কেবল কয়েকটি নির্দিষ্ট ধরণের জন্য এটি করতে হয় তবে আপনি সাধারণ সিরিয়ালাইজেশন কাঠামোটি নিয়ে আসার চেষ্টা করবেন না। আপনার প্রয়োজন সমস্ত প্রকারে কেবলমাত্র একটি উদাহরণ পদ্ধতি এবং একটি স্থিতিশীল পদ্ধতি প্রয়োগ করুন:

public void WriteTo(Stream stream)
public static WhateverType ReadFrom(Stream stream)

একটি বিষয় মনে রাখবেন: আপনি যদি উত্তরাধিকারের সাথে জড়িত হন তবে সবকিছু আরও জটিল হয়ে ওঠে। উত্তরাধিকার ব্যতীত, আপনি কী ধরণের সাথে শুরু করছেন তা যদি জানেন তবে আপনাকে কোনও ধরণের তথ্য অন্তর্ভুক্ত করার দরকার নেই। অবশ্যই, সংস্করণকরণের বিষয়টিও রয়েছে - আপনার ধরণের বিভিন্ন সংস্করণের সাথে পশ্চাদপদ এবং ফরোয়ার্ডের সামঞ্জস্যতা সম্পর্কে আপনার কি চিন্তা করা দরকার?


এটিকে "প্রোটোবুফ-সিশার্প-পোর্ট" (গুগল কোড), বা "ডটনেট-প্রোটোবুফস" (গিট) হিসাবে উল্লেখ করা কি আমার পক্ষে আরও সঠিক?
— মার্ক গ্র্যাভেল

4
অবজেক্টের বাইটগুলি ধারণ করতে আমার বাইনারি ফাইলটি দরকার। কেবল বাইটস, কোনও মেটাডেটা নেই। বস্তু থেকে বস্তু প্যাক করা। তাই আমি কাস্টম সিরিয়ালাইজেশন প্রয়োগ করব।
— chuckhlogan

6
শূন্য মেটাডেটার ঝুঁকি হ'ল আপনি তখন খুব সংস্করণ-অসহিষ্ণু হন কারণ এটি খুব দেরী হওয়ার আগে নমনীয়তার অনুমতি দেওয়ার খুব কম উপায় রয়েছে। প্রোটোকল বাফারগুলি বেশ ডেটা-ঘন। আপনার কি সত্যিই স্ক্রুটির অতিরিক্ত বাড়তি দরকার?
— মার্ক গ্র্যাভেল

@ মার্ক: এবং অবশ্যই পূর্ণসংখ্যার জন্য, পিবি কাঁচা বাইটের চেয়ে কম হয়ে যেতে পারে ...
— জন স্কিপ

16

আমি ক্রিস্টালোনিক্সের উত্তর নিয়েছি এবং সেগুলি এক্সটেনশন পদ্ধতিতে পরিণত করেছি। আমি আশা করি অন্য কেউ তাদের দরকারী বলে মনে করবে:

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

public static T Deserialize<T>(this byte[] byteArray) where T : class
{
    if (byteArray == null)
    {
        return null;
    }
    using (var memStream = new MemoryStream())
    {
        var binForm = new BinaryFormatter();
        memStream.Write(byteArray, 0, byteArray.Length);
        memStream.Seek(0, SeekOrigin.Begin);
        var obj = (T)binForm.Deserialize(memStream);
        return obj;
    }
}

4
এই এক সত্যিই দরকারী এবং সহজ !! ধন্যবাদ.
— মিঃ হিডেন

13

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

.NET এ কয়েকটি বাস্তবায়ন রয়েছে; নির্দিষ্টভাবে

আমি নম্রভাবে যুক্তি দিয়ে বলতে পারি যে প্রোটোবুফ-নেট (যা আমি লিখেছি) আরও বেশি। নেট সিড ক্লাস ("নিয়মিত" প্রোটোকল-বাফারদের কোড-জেনারেশন দাবি করার প্রবণতা) দিয়ে নেট-ইডিয়োমেটিক ব্যবহারের অনুমতি দেয় ; উদাহরণ স্বরূপ:

[ProtoContract]
public class Person {
   [ProtoMember(1)]
   public int Id {get;set;}
   [ProtoMember(2)]
   public string Name {get;set;}
}
....
Person person = new Person { Id = 123, Name = "abc" };
Serializer.Serialize(destStream, person);
...
Person anotherPerson = Serializer.Deserialize<Person>(sourceStream);

4
এমনকি "সংশ্লেষ চিহ্নিতকারী" এখনও মেটাডেটা। ওপি কী চেয়েছিল সে সম্পর্কে আমার বোঝার বিষয়টি অবজেক্টের ডেটা ছাড়া কিছুই ছিল না। সুতরাং, উদাহরণস্বরূপ, যদি বস্তুটি 2 32-বিট পূর্ণসংখ্যার সাথে একটি কাঠামো হয়, তবে তিনি ফলাফলটি 8 বাইটের বাইট অ্যারে হিসাবে প্রত্যাশা করবেন।
— ব্যবহারকারী316117

@ ব্যবহারকারী316117 যা সংস্করণে আসল ব্যথা। প্রতিটি পদ্ধতির সুবিধা এবং অসুবিধা রয়েছে।
— মার্ক Gravell


প্রোটো * অ্যাট্রিবিউটগুলি ব্যবহার এড়াতে কি উপায় আছে? আমি যে সত্তাগুলি ব্যবহার করতে চাই তা তৃতীয় পক্ষের লাইব্রেরিতে রয়েছে।
— অ্যালেক্স 75

5

এটি আমার পক্ষে কাজ করেছে:

byte[] bfoo = (byte[])foo;

foo একটি অবজেক্ট যা আমি 100% নির্দিষ্ট এটি বাইট অ্যারে।


2

কটাক্ষপাত ধারাবাহিকতাতে , "রূপান্তর করুন" একটি বাইট প্রবাহে একটি সম্পূর্ণ বস্তু একটি কৌশল। আপনি এটি নেটওয়ার্কে প্রেরণ করতে পারেন বা এটি একটি ফাইলে লিখতে পারেন এবং পরে এটি কোনও বস্তুর কাছে পুনরায় ফিরিয়ে আনতে পারেন।


আমি মনে করি চুকলোগন স্পষ্টভাবে তা অস্বীকার করেছে (ফর্ম্যাটর == সিরিয়ালাইজেশন)।
— হেন্ক হলটারম্যান

@ হেন্ক - কারণগুলি কী তা নির্ভর করে ; তিনি অতিরিক্ত তথ্য উল্লেখ করেছিলেন, যা আমি টাইপ মেটাটাটা এবং ক্ষেত্রের তথ্য হিসাবে গ্রহণ করি; আপনি যে ওভারহেড ছাড়াই সিরিয়ালাইজেশন ব্যবহার করতে পারেন; শুধু সাথে না BinaryFormatter।
— মার্ক Gravell

2

আমি কোনও জিনিসকে বাইটে রূপান্তর করার জন্য অন্য উপায় খুঁজে পেয়েছি [], এটি আমার সমাধান:

IEnumerable en = (IEnumerable) myObject;
byte[] myBytes = en.OfType<byte>().ToArray();

শ্রদ্ধা


1

কোনও অবজেক্টের স্মৃতি সরাসরি অ্যাক্সেস করতে ("কোর ডাম্প" করতে) আপনাকে অনিরাপদ কোডে যেতে হবে।

আপনি যদি বাইনারিউইটারের চেয়ে আরও কমপ্যাক্ট চান বা কোনও কাঁচা মেমরি ডাম্প আপনাকে দেয়, তবে আপনাকে কিছু কাস্টম সিরিয়ালাইজ কোড লিখতে হবে যা অবজেক্ট থেকে গুরুতর তথ্য বের করে এবং এটি একটি অনুকূল উপায়ে প্যাক করে।

পিএস সম্পাদনা করুন ডেটা সংকোচনের জন্য বাইনারি রাইটার পদ্ধতির একটি ডিফলেট স্ট্রিমে মোড়ানো খুব সহজ, যা সাধারণত ডেটা আকারকে প্রায় অর্ধেক করে দেবে।


4
অনিরাপদ কোডটি যথেষ্ট নয়। সি # এবং সিএলআর আপনাকে অনিরাপদ কোডে এমনকি কোনও পরিচালিত অবজেক্টে কাঁচা পয়েন্টার নিতে বা ইউনিয়নে দুটি অবজেক্ট রেফারেন্স রাখতে দেয় না।
— পাভেল মিনায়েভ

1

আমি বিশ্বাস করি আপনি যা করার চেষ্টা করছেন তা অসম্ভব। আপনার প্রোগ্রামটি বন্ধ হয়ে যাওয়ার পরে ফাইল থেকে বস্তুটি পুনরুদ্ধার করা আবশ্যক

জাঙ্ক BinaryFormatter।
তবে অবজেক্টের ডেটা পাওয়া সম্ভব, আপনাকে কেবল এর সঠিক আকারটি জানতে হবে (এটির চেয়ে বেশি কঠিন):

public static unsafe byte[] Binarize(object obj, int size)
{
    var r = new byte[size];
    var rf = __makeref(obj);
    var a = **(IntPtr**)(&rf);
    Marshal.Copy(a, r, 0, size);
    return res;
}

এটি এর মাধ্যমে পুনরুদ্ধার করা যেতে পারে:

public unsafe static dynamic ToObject(byte[] bytes)
{
    var rf = __makeref(bytes);
    **(int**)(&rf) += 8;
    return GCHandle.Alloc(bytes).Target;
}

উপরোক্ত পদ্ধতিগুলি সিরিয়ালাইজেশনের জন্য কাজ না করার কারণটি হ'ল প্রত্যাবর্তিত তথ্যগুলিতে প্রথম চারটি বাইট একটি এর সাথে সম্পর্কিত RuntimeTypeHandle। RuntimeTypeHandleবস্তুর বিন্যাস / টাইপ বর্ণনা কিন্তু এটি এর মান প্রত্যেক সময় দৌড়ে প্রোগ্রাম পরিবর্তন।

সম্পাদনা: এটি নির্বোধ যে এটি করবেন না -> যদি আপনি ইতিমধ্যে নির্দিষ্টভাবে অবজেক্টটির ডিসরিয়ালাইজড হওয়ার ধরণটি জানেন তবে deserialization BitConvertes.GetBytes((int)typeof(yourtype).TypeHandle.Value)করার সময় আপনি সেই বাইটগুলি স্যুইচ করতে পারেন ।

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