如何在 C# 流中读取非托管内存流?

发布于 2024-08-03 10:22:56 字数 145 浏览 7 评论 0原文

我可以使用 UnmanagedMemoryStream 读取 C# 中的非托管内存,但如何执行相反的操作呢?

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

I can read unmanaged memory in C# using UnmanagedMemoryStream, but how can I do the reverse?

I want to read from a managed stream directly into unmanaged memory, instead of first reading into a byte[] and then copying. I'm doing async stream reading on a large number of requests, so the added memory is significant (not to mention the additional copy).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

终止放荡 2024-08-10 10:22:56

如果您有已知的目标缓冲区并且知道数据有多大,这实际上并不太难。再次强调,关键的实现是 UnmanagementMemoryStream只是一系列本机字节的薄包装。

您想要做的是以通常的方式获取指向本机目标缓冲区的指针。然后您可以在其之上构造一个可写 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.
}

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.

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. 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:

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.
}
半山落雨半山空 2024-08-10 10:22:56

我认为这实际上是不可能的。当您谈论托管流时,我想您指的是 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 可能会在内存中移动数组。如果您将指针传递给某个继续在不同线程中运行的“不安全”函数,则该指针将指向无效的内存位置。

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.

The members of this class take byte[] as a parameter, and that is a managed class.

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

魂归处 2024-08-10 10:22:56

托管流始终需要一个对有效 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
}

The managed stream will always need a "managed" object reference to a valid byte[] object. 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[] 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
}
归属感 2024-08-10 10:22:56

您可以使用 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);
}

You can use C# and read file by Windows API directly into unmanaged memory.

If you want to read from FileStream, this could be helpful. Check FileStream implementation and do something similar.

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文