我知道这已经得到了回答,但在阅读了其他问题后,我仍然没有解决方案。我有一个用以下C ++结构编写的文件:
typedef struct myStruct{
char Name[127];
char s1[2];
char MailBox[149];
char s2[2];
char RouteID[10];
} MY_STRUCT;
我的方法是能够在结构中一次解析一个字段,但我的问题是我无法正确解析s1和MailBox。在该文件中,s1字段包含“\ r \ n”(二进制0D0A),这导致我的解析代码无法正确解析MailBox字段。这是我的解析代码:
[StructLayout(LayoutKind.Explicit, Size = 0x80 + 0x2 + 0x96)]
unsafe struct MY_STRUCT
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x80)]
public string Name;
[FieldOffset(0x80)]
public fixed char s1[2];
/* Does not work, "Could not load type 'MY_STRUCT' ... because it contains an object field at offset 130 that is incorrectly aligned or overlapped by a non-object field." */
[FieldOffset(0x80 + 0x2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x96)]
public string MailBox;
}
如果我注释掉最后一个字段并将struct的大小减小到0x80 + 0x2,它将对前两个变量正常工作。
有一点需要注意的是,Name和Mailbox字符串包含空终止字符,但由于s1没有空终止字符,所以它似乎搞乱了解析器,但我不知道为什么因为我看起来代码明确告诉Marshaler结构中的s1字段只是一个固定的2-char缓冲区,而不是以null结尾的字符串。
这是我的测试数据的图片(在代码中我搜索过BinaryReader中的第一行,因此“Name”从0x0开始,而不是0x10)。
答案 0 :(得分:1)
这是一种方式,它不使用unsafe
(也不是特别优雅/高效)
using System.Text;
using System.IO;
namespace ReadCppStruct
{
/*
typedef struct myStruct{
char Name[127];
char s1[2];
char MailBox[149];
char s2[2];
char RouteID[10];
} MY_STRUCT;
*/
class MyStruct
{
public string Name { get; set; }
public string MailBox { get; set; }
public string RouteID { get; set; }
}
class Program
{
static string GetString(Encoding encoding, byte[] bytes, int index, int count)
{
string retval = encoding.GetString(bytes, index, count);
int nullIndex = retval.IndexOf('\0');
if (nullIndex != -1)
retval = retval.Substring(0, nullIndex);
return retval;
}
static MyStruct ReadStruct(string path)
{
byte[] bytes = File.ReadAllBytes(path);
var utf8 = new UTF8Encoding();
var retval = new MyStruct();
int index = 0; int cb = 127;
retval.Name = GetString(utf8, bytes, index, cb);
index += cb + 2;
cb = 149;
retval.MailBox = GetString(utf8, bytes, index, cb);
index += cb + 2;
cb = 10;
retval.RouteID = GetString(utf8, bytes, index, cb);
return retval;
} // http://stackoverflow.com/questions/30742019/reading-binary-file-into-struct
static void Main(string[] args)
{
MyStruct ms = ReadStruct("MY_STRUCT.data");
}
}
}
答案 1 :(得分:0)
您的结构大小未正确添加。 MailBox大小为0x95,如MY_STRUCT中所列,而不是0x96,因为您在C#代码中调用它。
答案 2 :(得分:0)
以下是我如何让它为我工作:
public static unsafe string BytesToString(byte* bytes, int len)
{
return new string((sbyte*)bytes, 0, len).Trim(new char[] { ' ' }); // trim trailing spaces (but keep newline characters)
}
[StructLayout(LayoutKind.Explicit, Size = 127 + 2 + 149 + 2 + 10)]
unsafe struct USRRECORD_ANSI
{
[FieldOffset(0)]
public fixed byte Name[127];
[FieldOffset(127)]
public fixed byte s1[2];
[FieldOffset(127 + 2)]
public fixed byte MailBox[149];
[FieldOffset(127 + 2 + 149)]
public fixed byte s2[2];
[FieldOffset(127 + 2 + 149 + 2)]
public fixed byte RouteID[10];
}
在解析结构之后,我可以通过调用BytesToString方法来访问字符串,例如string name = BytesToString(record.Name, 127);
我注意到我不需要在StructLayout中使用Size属性,我不确定保留或删除它的最佳做法是什么?