加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
C#中读写byte[]数组中的结构体
acmilan2016/06/08软件综合 IP:四川

C++中,可以通过指针强制转换来读取char[]中的结构体,但是到了C#中,这一招行不通了。

通过查找资料发现,在C#中可以有多种读取byte[]中的结构体的方法,但是我感觉最可靠的还是使用BitConverter:

  • 从byte[]读取字段,使用field = BitConverter.ToXXX(bytes, offset)实现。
  • 向byte[]写入字段,使用BitConverter.GetBytes(field).CopyTo(bytes, offset)实现。

注意定长字符串不能用BitConverter.ToString,它是用来返回16进制表示的。对于定长字符串来说:

  • 从byte[]读取定长字符串,可以这样实现:
Other
field = Encoding.XXX.GetString(bytes, offset, length).Split('\0')[0];
  • 向byte[]写入定长字符串就麻烦点了,因为需要控制缓冲区长度:
Other
byte[] data = new byte[length]; Encoding.XXX.GetBytes(field).CopyTo(data, 0); data.CopyTo(bytes, offset);

示例代码如下:

Other
public enum BICompression : uint { BI_RGB = 0, // 不压缩 BI_RLE8 = 1, // 8位运行长度编码 BI_RLE4 = 2, // 4位运行长度编码 BI_BITFIELDS = 3 // 使用颜色位屏蔽 } public struct BitmapInfoHeader { public uint biSize; // 结构的大小>=40 public int biWidth; // 图像宽度(像素) public int biHeight; // 图像高度(像素) public ushort biPlanes; // = 1 public ushort biBitCount; // 每像素的位数(1,4,8,16,24,32) public BICompression biCompression; // 压缩代码 public uint biSizeImage; // 图像的字节数 public int biXPelsPerMeter; // 横向分辨率 public int biYPelsPerMeter; // 纵向分辨率 public uint biClrUsed; // 使用的颜色数 public uint biClrImportant; // 重要颜色数 public BitmapInfoHeader(byte[] src, int off) { biSize = BitConverter.ToUInt32(src, off); biWidth = BitConverter.ToInt32(src, off + 4); biHeight = BitConverter.ToInt32(src, off + 8); biPlanes = BitConverter.ToUInt16(src, off + 12); biBitCount = BitConverter.ToUInt16(src, off + 14); biCompression = (BICompression)BitConverter.ToUInt32(src, off + 16); biSizeImage = BitConverter.ToUInt32(src, off + 20); biXPelsPerMeter = BitConverter.ToInt32(src, off + 24); biYPelsPerMeter = BitConverter.ToInt32(src, off + 28); biClrUsed = BitConverter.ToUInt32(src, off + 32); biClrImportant = BitConverter.ToUInt32(src, off + 36); } public void WriteBytes(byte[] dst, int off) { BitConverter.GetBytes(biSize).CopyTo(dst, off); BitConverter.GetBytes(biWidth).CopyTo(dst, off + 4); BitConverter.GetBytes(biHeight).CopyTo(dst, off + 8); BitConverter.GetBytes(biPlanes).CopyTo(dst, off + 12); BitConverter.GetBytes(biBitCount).CopyTo(dst, off + 14); BitConverter.GetBytes((uint)biCompression).CopyTo(dst, off + 16); BitConverter.GetBytes(biSizeImage).CopyTo(dst, off + 20); BitConverter.GetBytes(biXPelsPerMeter).CopyTo(dst, off + 24); BitConverter.GetBytes(biYPelsPerMeter).CopyTo(dst, off + 28); BitConverter.GetBytes(biClrUsed).CopyTo(dst, off + 32); BitConverter.GetBytes(biClrImportant).CopyTo(dst, off + 36); } }

[修改于 8年11个月前 - 2016/06/09 10:34:28]

来自:计算机科学 / 软件综合
4
新版本公告
~~空空如也
acmilan 作者
8年11个月前 修改于 8年11个月前 IP:四川
821141

对于和一般的WinAPI交互来说,没必要这么麻烦,可以使用StructLayout和MarshalAs解决:

Other
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace ConsoleApplication5 { class Program { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct RtlOSVersionInfoExW { public uint dwOSVersionInfoSize; public uint dwMajorVersion; public uint dwMinorVersion; public uint dwBuildNumber; public uint dwPlatformId; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szCSDVersion; public ushort wServicePackMajor; public ushort wServicePackMinor; public ushort wSuiteMask; public byte wProductType; public byte wReserved; } [DllImport("ntdll.dll")] public static extern bool RtlGetVersion(ref RtlOSVersionInfoExW osver); static void Main(string[] args) { RtlOSVersionInfoExW osvex = new RtlOSVersionInfoExW(); osvex.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvex); RtlGetVersion(ref osvex); Console.WriteLine(osvex.dwMajorVersion); Console.WriteLine(osvex.dwMinorVersion); Console.WriteLine(osvex.dwBuildNumber); Console.WriteLine(osvex.dwPlatformId); Console.WriteLine(osvex.szCSDVersion); Console.WriteLine(osvex.wServicePackMajor); Console.WriteLine(osvex.wServicePackMinor); Console.WriteLine(osvex.wSuiteMask); Console.WriteLine(osvex.wProductType); Console.WriteLine(osvex.wReserved); } } }
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹
8年11个月前 IP:江苏
821213

/// <summary>
/// 结构体 值类型转byte数组
/// BitConverter
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="structObj"></param>
/// <returns></returns>
public static byte[] StructToBytes<T>(this T structObj) where T : struct
{
int size = System.Runtime.InteropServices.Marshal.SizeOf(structObj);
byte[] bytes = new byte[size];

Other
IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); System.Runtime.InteropServices.Marshal.StructureToPtr(structObj, structPtr, true); System.Runtime.InteropServices.Marshal.Copy(structPtr, bytes, 0, size); System.Runtime.InteropServices.Marshal.FreeHGlobal(structPtr); return bytes; } /// <summary> /// byte数组转 结构体 值类型 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="bytes"> /// <returns></returns> public static T BytesToStuct<t>(this byte[] bytes) where T : struct { int size = System.Runtime.InteropServices.Marshal.SizeOf(default(T)); if (size > bytes.Length) { return default(T); } IntPtr structPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); System.Runtime.InteropServices.Marshal.Copy(bytes, 0, structPtr, size); T obj = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(structPtr, typeof(T)); System.Runtime.InteropServices.Marshal.FreeHGlobal(structPtr); return obj; } </t>

/// <summary>
/// 把对象序列化并返回相应的字节
/// </summary>
/// <param name="pObj">需要序列化的对象</param>
/// <returns>byte[]</returns>
static public byte[] SerializeObject(this object pObj)
{
if (pObj == null)
return null;
System.IO.MemoryStream _memory = new System.IO.MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(_memory, pObj);
_memory.Position = 0;
byte[] read = new byte[_memory.Length];
_memory.Read(read, 0, read.Length);
_memory.Close();
return read;
}

Other
/// <summary> /// 把字节反序列化成相应的对象 /// </summary> /// <param name="pBytes">字节流 /// <returns>object</returns> static public T DeserializeObject<t>(this byte[] pBytes) { T _newOjb ; if (pBytes == null || pBytes.Length < 1) return default(T); System.IO.MemoryStream _memory = new System.IO.MemoryStream(pBytes); _memory.Position = 0; BinaryFormatter formatter = new BinaryFormatter(); _newOjb = (T)formatter.Deserialize(_memory); _memory.Close(); return _newOjb; } </t>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
8年11个月前 IP:四川
821250

引用 张静茹 : /// <summary> /// 结构体 值类型转byte数组 /// BitConverter /// </summary> ///……

写个算法也要用到互操作性,总感觉不爽。。。

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
novakon
8年11个月前 修改于 8年11个月前 IP:广东
821452

InteropServices.Marshal Methods are probably the fastest way to manipulate bytes directly from memory in .NET

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,6年3个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的