2015-06-13 71 views
3

我无法转换字节数组的字符串部分。字节数组结构

我的结构是这样的:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct Message 
{ 
    public int id; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string text; 
} 

测试字节数组的创建:

private static byte[] CreateMessageByteArray() 
{ 
    int id = 69; 
    byte[] intBytes = BitConverter.GetBytes(id); 

    string text = "test"; 
    byte[] stringBytes = GetBytes(text); 

    IEnumerable<byte> rv = intBytes.Concat(stringBytes); 

    return rv.ToArray(); 
} 

方法到我的字节组转换成一个结构:

static T ByteArrayToStructure<T>(byte[] bytes) where T : struct 
{ 
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    var result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 
    return result; 
} 

当我打电话ByteArrayToStructureCreateMessageByteArray()的结果我得到一个id = 60和text =“t”的结构。

为什么我不能得到整个字符串,例如“测试”?

编辑: 这是我忘了填写Flash代码:

static byte[] GetBytes(string str) 
    { 
     byte[] bytes = new byte[str.Length * sizeof(char)]; 
     System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); 
     return bytes; 
    } 

回答

4

的问题是在这条线:

byte[] stringBytes = GetBytes(text); 

你是如何将字符串转换为一个字节数组?你可能使用Unicode编码,将每个字符存储为两个字节,因为你的字符串是ASCII字符集,所有其他字节将是零:

byte[] stringBytes = new UnicodeEncoding().GetBytes(text); 
// will give you { 't', '\0', 'e', '\0', 's', '\0', 't', '\0' } 

这些零误导编组机制引入假设他们是终端字符,所以字符串在't'之后结束。

相反,可以使用ASCII编码(其存储每个字符一个字节):

byte[] stringBytes = new ASCIIEncoding().GetBytes(text); 
// will give you { 't', 'e', 's', 't' } 
// but will lose non-ASCII character information 

或者可以使用一个UTF8编码(这是可变长度):

byte[] stringBytes = new UTF8Encoding().GetBytes(text); 
// will give you { 't', 'e', 's', 't' }  
// and retain non-ASCII character information, but it's somewhat 
// trickier to rebuild the string correctly in case of non-ASCII 
// information present 
+1

我猜想为MarshalAs属性添加“CharSet = CharSet.Unicode”也可以。 – cubrr

1

也许如您所愿GetBytes方法不起作用。 这linqpad为我工作得很好:

void Main() 
{ 
    var result = ByteArrayToStructure<Message>(CreateMessageByteArray()); 
    result.Dump(); 
} 

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct Message 
{ 
    public int id; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string text; 
} 

private static byte[] CreateMessageByteArray() 
{ 
    int id = 69; 
    byte[] intBytes = BitConverter.GetBytes(id); 

    string text = "test"; 
    byte[] stringBytes = Encoding.UTF8.GetBytes(text); 

    IEnumerable<byte> rv = intBytes.Concat(stringBytes); 

    return rv.ToArray(); 
} 

static T ByteArrayToStructure<T>(byte[] bytes) where T : struct 
{ 
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    var result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 
    return result; 
} 

输出:

id 69 
text test 
4

在除了其他两个答案之外,如果您希望text字段中的字符串始终为Unicode,则可以在您的[StructLayout]属性中包含CharSet = CharSet.Unicode属性