简体   繁体   English

我怎样才能在 C# stream.Read 到非托管内存流?

[英]How can I in C# stream.Read into unmanaged memory stream?

I can read unmanaged memory in C# using UnmanagedMemoryStream, but how can I do the reverse?我可以使用 UnmanagedMemoryStream 在 C# 中读取非托管内存,但我该怎么做呢?

I want to read from a managed stream directly into unmanaged memory, instead of first reading into a byte[] and then copying.我想从托管流直接读入非托管内存,而不是先读入 byte[] 然后复制。 I'm doing async stream reading on a large number of requests, so the added memory is significant (not to mention the additional copy).我正在对大量请求进行异步流读取,因此增加的内存很重要(更不用说额外的副本了)。

This actually isn't too hard if you have a known destination buffer and you know how big your data is.如果您有一个已知的目标缓冲区并且知道您的数据有多大,这实际上并不太难。 The key realization, once again, is that an UnmanagedMemoryStream is just a thin wrapper around a sequence of native bytes.再一次,关键的实现是UnmanagedMemoryStream只是一系列本机字节的薄包装器。

What you want to do is grab a pointer to your native destination buffer in the usual fashion.你想要做的是以通常的方式获取一个指向你的本地目标缓冲区的指针。 Then you can construct a writable UnmanagedMemoryStream on top of it.然后你可以在它之上构造一个可写UnmanagedMemoryStream Copy your source stream to the destination stream and voila.将您的源流复制到目标流,瞧。 A single copy has moved you from the managed memory world to the native memory world, In C++/CLI: it looks something like this:单个副本已将您从托管内存世界转移到本机内存世界,在 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.
}

I think that it is not really possible.我认为这是不可能的。 When you talk about a managed stream, I suppose you are refering to an instance of System.IO.Stream or a subclass hereof.当您谈论托管流时,我想您指的是 System.IO.Stream 的实例或其子类。

The members of this class take byte[] as a parameter, and that is a managed class.该类的成员以byte[]为参数,即为托管类。

I guess that the closest you can come is creating a managed byte[], and then creating a byte* in an unsafe block, and then passing the byte* to whatever needs an unmanaged reference:我想最接近的是创建一个托管字节[],然后在不安全块中创建一个字节*,然后将字节*传递给任何需要非托管引用的地方:

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 
    }
}

But that is not exactly what you're asking for但这并不是你要的

edit : Be careful though.编辑:不过要小心。 You mention something about async reads.您提到了有关异步读取的内容。 As soon as you're outside the fixed boundary, the GC may move the array around in memory.一旦您超出固定边界,GC 可能会在内存中移动数组。 And if you've passed the pointer to some "unsafe" function that continues to operate in a different thread, the pointer will point to an invalid memory location.如果您已将指针传递给某个继续在不同线程中运行的“不安全”函数,则该指针将指向无效的内存位置。

The managed stream will always need a "managed" object reference to a valid byte[] object.托管流将始终需要对有效byte[]对象的“托管”对象引用。 However, you can use a managed byte[] which is pinned en lieu of a unmanaged memory allocation and therefore make it accessible as an unmanaged memory block also:但是,您可以使用固定的托管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(); // but make sure that no unmanaged code uses the pinned data anymore upon release
}

You can use C# and read file by Windows API directly into unmanaged memory.您可以使用 C# 并通过 Windows API 将文件直接读取到非托管内存中。

If you want to read from FileStream, this could be helpful.如果您想从 FileStream 中读取,这可能会有所帮助。 Check FileStream implementation and do something similar.检查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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM