2014-06-20 6 views
7

को फिक्स्ड वस्तु मैं एक साधारण उद्देश्य यह है कि इस तरह दिखता है:बाइट सरणी

public class Foo 
{ 
    public UInt32 One { get; set; } 
    public UInt32 Two { get; set; } 
    public UInt32 Three { get; set; } 
    public UInt32 Four { get; set; } 
} 

मैं इस कोड मैं नेट पर कहीं पाया की कोशिश की:

public byte[] ObjectToByteArray(Object obj) 
{ 
    MemoryStream fs = new MemoryStream(); 
    BinaryFormatter formatter = new BinaryFormatter(); 
    formatter.Serialize(fs, obj); 
    byte[] rval = fs.ToArray(); 
    fs.Close(); 
    return rval; 
} 

लेकिन किसी भी तरह लौटने बाइट सरणी 248 बाइट्स का आकार।
मैं इसे 4 बाइट एक्स 4 क्षेत्रों = 16 बाइट्स होने की अपेक्षा करेंगे।

प्रश्न:
स्पष्ट तरीका एक बाइट सरणी में एक निश्चित वस्तु कन्वर्ट करने के लिए क्या है? इस मामले में आकार में
और जिसके परिणामस्वरूप सरणी होना चाहिए 16 बाइट्स?

उत्तर

6

BinaryFormatter के साथ यह कर करेंगे प्रकार की जानकारी का एक बहुत बचत होती है ठीक से deserialize करने में सक्षम हो। आप कुछ सख्त प्रोटोकॉल के माध्यम से comunicate करने के लिए कॉम्पैक्ट क्रमबद्धता या चाहते हैं, तो आप इस तरह explictly यह करना होगा:

public byte[] ToByteArray() 
{ 
    List<byte> result = new List<byte>(); 

    result.AddRange(BitConverter.GetBytes(One)); 
    result.AddRange(BitConverter.GetBytes(Two)); 
    result.AddRange(BitConverter.GetBytes(Three)); 
    result.AddRange(BitConverter.GetBytes(Four)); 

    return result.ToArray(); 
} 
यहाँ

मैं बाइट सरणी में अपने UInt32 में से प्रत्येक को बदलने और सरणी जिसके परिणामस्वरूप में संग्रहीत।

संपादित
बाहर बदल जाता है वहाँ struct और Marshal सबसे पहले आप struct बनाने का उपयोग करके एक और तरीका है और उस जैसी विशेषताओं के चिह्नित:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 
    public string StringField; 

    public int IntField; 
} 

यहाँ LayoutKind.Sequential clr स्मृति में खेतों रखने के लिए बताता है घोषणा के रूप में एक ही क्रम में। Pack = 1 संरचनाओं के बिना आवश्यकतानुसार अधिक स्मृति ले सकते हैं। जैसा struct एक short क्षेत्र और एक byte जरूरतों केवल 3 बाइट्स, लेकिन डिफ़ॉल्ट रूप से साथ यह आकार सबसे अधिक संभावना हो जाएगा 4 (प्रोसेसर एकल बाइट जोड़ तोड़ के लिए निर्देश, 2 बाइट्स और 4 बाइट, clr बलिदान struct के कहने के अनुसार एक बाइट मात्रा को कम करने के लिए किया आधे से मशीन कोड के निर्देशों के)। अब आप बाइट्स कॉपी करने के लिए Marshal उपयोग कर सकते हैं:

public static byte[] GetBytes<T>(T str) 
{ 
    int size = Marshal.SizeOf(str); 
    var bytes = new byte[size]; 
    IntPtr ptr = Marshal.AllocHGlobal(size); 

    try 
    { 
     Marshal.StructureToPtr(str, ptr, true); 
     Marshal.Copy(ptr, bytes, 0, size); 
     return bytes; 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(ptr); 
    } 
} 

सब कुछ सरल प्रकार के साथ ठीक काम करता है। इस तरह के string के रूप में जटिल प्रकार के लिए आप MarshalAs विशेषता का उपयोग करना होगा और यह उपयोग कर रहा है है में थोड़ा और अधिक जटिल (उदाहरण में मैं clr बताया तय 50 बाइट्स आकार की सरणी के रूप में स्ट्रिंग मार्शल करने के लिए)।

2

ध्यान रखें कि जब आप BinaryFormatter के साथ एक वस्तु serialise, आप प्रकार की जानकारी जैसी चीज़ों सहित रहे हैं। जिसके परिणामस्वरूप आप देख रहे हैं।

यदि आप किसी वस्तु को (इस मामले में) केवल 16 बाइट्स में क्रमबद्ध करना चाहते हैं तो आपको इसे StreamWriter जैसे कुछ मैन्युअल रूप से करने की आवश्यकता होगी।

तो आकार कोई मुद्दा नहीं है तो इस मामले में एक BinaryFormatter गलत नहीं है और यह करने के लिए ज्यादा कोड नहीं ले करता है, लेकिन यह यह करने का सबसे कारगर तरीका स्मृति नहीं है।

संपादित करें: यहाँ कैसे आप एक StreamWriter

System.IO.MemoryStream stream = new System.IO.MemoryStream(); 

StreamWriter writer = new StreamWriter(stream); 

writer.Write(myObject.One); // here's where we actually write the data to the stream 
writer.Write(myObject.Two); 
writer.Write(myObject.Three); 
writer.Write(myObject.Four);  

writer.Flush(); // make sure all the data in the stream writer ends up in the 
        // underlying stream 

byte[] result = stream.ToArray(); // here's your resulting byte array 

stream.Dispose(); // don't forget to dispose of the stream!   
+0

इसे 16 बाइट हां होना चाहिए। कोई सुझाव मुझे स्ट्रीमवाइटर का उपयोग कैसे करना चाहिए ?? –

+0

मैंने अपना जवाब संपादित कर लिया है। परिणामी बाइट सरणी 16 बाइट्स होनी चाहिए यदि आप इसे सुझाते हैं। ध्यान दें कि यह केवल नमूना कोड है। मैंने इसका परीक्षण नहीं किया है, न ही यह 'उपयोग' कथन का उपयोग करता है जिसे आपको उन वस्तुओं के लिए उपयोग करना चाहिए जो 'IDISposable' जैसे 'मेमोरीस्ट्रीम' को लागू करते हैं। आप इसे अपने फू ऑब्जेक्ट में एक फ़ंक्शन बनाने का निर्णय ले सकते हैं, ताकि आप अपने बाइट सरणी प्राप्त करने के लिए foo.Serialize() को कॉल कर सकें। –

2

मैन्युअल रूप से ऐसा करने का एक तरीका है जो 16-बाइट्स की गारंटी देगा।

using System; 
using System.IO; 
using System.Linq; 

public class Foo 
{ 
    public UInt32 One { get; set; } 
    public UInt32 Two { get; set; } 
    public UInt32 Three { get; set; } 
    public UInt32 Four { get; set; } 

    public Foo() {} 

    public Foo(byte[] array) 
    { 
     One = BitConverter.ToUInt32(array,0);  
     Two = BitConverter.ToUInt32(array,4); 
     Three = BitConverter.ToUInt32(array,8);  
     Four = BitConverter.ToUInt32(array,12);  
    } 
    public byte[] toByteArray() 
    { 
     byte[] retVal = new byte[16]; 
     byte[] b = BitConverter.GetBytes(One); 
     Array.Copy(b, 0, retVal, 0, 4); 
     b = BitConverter.GetBytes(Two); 
     Array.Copy(b, 0, retVal, 4, 4); 
     b = BitConverter.GetBytes(Three); 
     Array.Copy(b, 0, retVal, 8, 4); 
     b = BitConverter.GetBytes(Four); 
     Array.Copy(b, 0, retVal, 12, 4); 
     return retVal; 
    } 
} 
public class P{ 
    public static void Main(string[] args) { 
     Foo foo = new Foo(); 
     foo.One = 1; 
     foo.Two = 2; 
     foo.Three = 3; 
     foo.Four = 4; 

     byte[] arr = foo.toByteArray(); 
     Console.WriteLine(arr.Length); 


     Foo bar = new Foo(arr); 
     Console.WriteLine(string.Format("{0} {1} {2} {3}", bar.One, bar.Two, bar.Three, bar.Four)); 

    } 
} 

आउटपुट:

16 
1 2 3 4 
2

यहाँ एक और तरीका है ... जो तरीका सबसे अच्छा है राय शायद की बात है है। मुझे एटमोस का जवाब पसंद है। कास्ट ऑपरेटर ओवरलोड के साथ उस उत्तर को मिलाएं और आपके पास एक सुंदर सुरुचिपूर्ण समाधान है।

class Foo 
{ 
    public UInt32 One { get; set; } 
    public UInt32 Two { get; set; } 
    public UInt32 Three { get; set; } 
    public UInt32 Four { get; set; } 

    static public implicit operator byte[](Foo f) 
    { 
     MemoryStream m = new MemoryStream(16); 
     BinaryWriter w = new BinaryWriter(m); 

     w.Write(f.One); 
     w.Write(f.Two); 
     w.Write(f.Three); 
     w.Write(f.Four); 
     w.Close(); 
     m.Close(); 

     return m.ToArray(); 
    } 

    static public explicit operator Foo(byte[] b) 
    { 
     Foo f = new Foo(); 
     MemoryStream m = new MemoryStream(b); 
     BinaryReader r = new BinaryReader(m); 

     f.One = r.ReadUInt32(); 
     f.Two = r.ReadUInt32(); 
     f.Three = r.ReadUInt32(); 
     f.Four = r.ReadUInt32(); 

     r.Close(); 
     m.Close(); 

     return f; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo f = new Foo() { One = 1, Two = 2, Three = 3, Four = 4 }; 
     byte[] b = (byte[])f; 
     Console.WriteLine(b.Length); 

     f = (Foo)b; 
     Console.WriteLine("{0} {1} {2} {3}", f.One, f.Two, f.Three, f.Four); 

     Console.ReadKey(true); 
    } 
}