我怎样才能在C#stream中进入非托管内存流?

我可以使用UnmanagedMemoryStream在C#中读取非托管内存,但是我该怎么做呢?

我想从托管流直接读入非托管内存,而不是先读入一个byte []然后再复制。 我正在对大量请求进行异步流读取,因此增加的内存很重要(更不用说额外的副本)。

我认为这不太可能。 当您谈论托管流时,我想您正在引用System.IO.Stream的实例或其子类。

这个类的成员将byte []作为参数,这是一个托管类。

我猜你最接近的是创建一个托管byte [],然后在一个不安全的块中创建一个byte *,然后将byte *传递给任何需要非托管引用的东西:

unsafe function test() { var buffer = new byte[1024]; fixed (byte* bufferPtr = &buffer[0]) { // Read bytes and pass the ptr to a function that needs to // operate on data directly } } 

但这并不是你所要求的

编辑 :但要小心。 你提到了有关异步读取的内容。 一旦你在固定边界之外,GC可以在内存中移动arrays。 如果您已将指针传递给某个继续在不同线程中运行的“不安全”函数,则指针将指向无效的内存位置。

如果您有一个已知的目标缓冲区并且您知道数据有多大,那么这实际上并不太难。 重要的实现是, UnmanagedMemoryStream只是一个本机字节序列的瘦包装器。

你想要做的是以通常的方式获取指向本机目标缓冲区的指针。 然后你可以在它上面构造一个可写的 UnmanagedMemoryStream 。 将源流复制到目标流并瞧! 单个副本将您从托管内存世界转移到本机内存世界。 在C ++ / CLI中,它看起来像这样:

 void CopyStreamToNativePtr(Stream^ src, unsigned char* dst) { // Assuming we want to start the copy at the beginning of src src->Seek(0, SeekOrigin::Begin); // Create an UnmanagedMemoryStream on top of the destination // with an appropriate size and capacity (We assume the buffer is // is sized to the source data in this function!) UnmanagedMemoryStream target(dst, src->Length, src->Length, FileAccess::Write); // Copy to your heart's content! src->CopyTo(%target); // We made the UnmanagedMemoryStream local so that we wouldn't have // to explicitly Dispose() of it. } 

托管流将始终需要对有效byte []对象的“托管”对象引用。 但是,您可以使用托管的byte[]代替非托管内存分配,因此也可以将其作为非托管内存块进行访问:

 byte[] data = new byte[]; GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned) try { IntPtr dataUnmanagedPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); // managed.Read(data, index, count); // use the unmanaged pointer here for unmanaged code } finally { pin.Free(pin); // but make sure that no unmanaged code uses the pinned data anymore upon release } 

您可以使用C#将Windows API直接读取到非托管内存中。

如果您想从FileStream中读取,这可能会有所帮助。 检查FileStream实现并执行类似的操作。

 var handle = Win32Native.SafeCreateFile(path, fAccess, share, secAttrs, mode, flagsAndAttributes, IntPtr.Zero); fixed(byte* p = bytes) { r = Win32Native.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero); }