是否可以在不执行 Marshal.Copy 的情况下将 IntPtr 转换为字节数组
本文关键字:转换 IntPtr 字节 数组 字节数 情况下 执行 Copy Marshal 是否 | 更新日期: 2023-09-27 18:27:55
我想将数据从 IntPtr 指针获取到字节数组中。 我可以使用以下代码来执行此操作:
IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
但是上面的代码强制将复制操作从 IntPtr 复制到字节数组中。当有问题的数据很大时,这不是一个好的解决方案。
有没有办法将 IntPtr 转换为字节数组? 例如,以下工作:
byte[] b = (byte[])intPtr
这将消除对复制操作的需要。
另外:我们如何确定 Intptr 指向的数据长度?
正如其他人所提到的,如果不复制(使用您提供的当前结构*(,就无法将数据存储在托管byte[]
中。但是,如果实际上不需要它位于托管缓冲区中,则可以使用 unsafe
操作直接处理非托管内存。这真的取决于你需要用它做什么。
所有byte[]
和其他引用类型都由 CLR 垃圾回收器管理,这是在不再使用内存时负责分配内存和释放内存的原因。返回GetBuffer
所指向的内存是由C++代码分配的非托管内存块,并且(内存布局/实现细节除外(基本上与 GC 托管内存完全分开。因此,如果要使用 GC 托管 CLR 类型 (byte[]
( 来包含当前保存在IntPtr
指向的非托管内存中的所有数据,则需要将其移动(复制(到 GC 知道的内存中。这可以通过Marshal.Copy
或使用unsafe
代码或 pinvoke 或其他内容的自定义方法来完成。
但是,这取决于您想用它做什么。你提到它是视频数据。如果要对数据应用一些转换或筛选器,可以直接在非托管缓冲区上执行此操作。如果要将缓冲区保存到磁盘,可以直接在非托管缓冲区上执行此操作。
关于长度问题,除非分配缓冲区的函数也告诉您长度是多少,否则无法知道非托管内存缓冲区的长度。正如评论者所提到的,这可以通过多种方式完成(结构的第一个字段,方法的参数(。
*最后,如果您控制了C++代码,则可以对其进行修改,使其不负责分配将数据写入的缓冲区,而是提供指向预分配缓冲区的指针。然后,可以在 C# 中创建预分配到C++代码所需大小的托管byte[]
,并使用 GCHandle
类型将其固定并提供指向C++代码的指针。
试试这个:
byte* b = (byte*)intPtr;
需要不安全(在函数签名、块或编译器标志/unsafe
中(。
不能让托管数组占用非托管内存。可以一次复制一个区块的非托管数据,并处理每个区块,也可以创建一个UnmanagedArray
类,该类采用IntPtr
并提供仍使用 Marshal.Copy 访问数据的索引器。
正如@Vinod所指出的,您可以使用unsafe
代码执行此操作。这将允许您使用类似 C 的指针直接访问内存。但是,在调用任何不安全的 .NET 方法之前,需要将数据封送到托管内存中,因此几乎只能使用自己的类似 C 的代码。我认为你根本不应该为此烦恼,只需用C++编写代码即可。
查看此代码项目页,了解使用非托管数组的解决方案。