【问题标题】:How to get the underlying file handle of a Stream?如何获取 Stream 的底层文件句柄?
【发布时间】:2011-12-27 02:27:18
【问题描述】:

我有一个使用物理内存快照(例如,VMware VMEM 文件)的应用程序。除其他外,它可以通过虚拟地址而不是物理地址从快照中读取进程/模块。这涉及通过页表一次重建 4KB 的模块,这反过来意味着对 Stream 的 Seek() 方法的大量调用。

由于我不确定的原因,这些对 Seek() 的调用使事情急剧下降。因此,我正在寻找一种解决方法——或者至少是一种解决托管 Seek() 实现的方法。我最好的猜测是 PInvoke SetFilePointer 并直接使用它,但为了做到这一点,我需要为 Stream 获取 IntPtr/SafeFileHandle。我有一些限制:

  1. 我使用的 API 仅限于 .NET 3.5,所以很遗憾 MemoryMappedFile 不是一个选项。

  2. 我不能使用 FileStream(它已经有一个可以通过反射访问的私有 SafeFileHandle 字段)或 PInvoke CreateFile() 以另一种方式获取快照——API 包括一个具有快照的排他锁。

当然,与 FileStream 不同,BinaryReader 及其底层 Stream 都没有对文件句柄的引用。但肯定存在一个吗?在这种情况下,我该如何获取它?

【问题讨论】:

  • 什么样的Stream?并非所有流都有文件句柄。
  • .NET 4.0 中的 MemoryMappedFile 只是原生 API 的托管包装器,您应该能够在 3.5 中轻松实现它(因此,我已经看到了很多实现)。就是说,在我看来,您主要是坚持使用文件系统(除了一些智能缓存)。到目前为止,内存映射文件可以在您描述的场景中为您提供最快的结果(与开箱即用的解决方案相比)。
  • @John Saunders:谢谢,您的问题促使我再次查看BinaryReader 类,然后我意识到我只需要将BaseStream 属性向下转换为FileStream,然后使用反射访问SafeFileHandle。如果您想写出来,我很乐意选择它作为正确答案。
  • @Polity:感谢您提供 MemoryMappedFile 提示。我一定会调查的。

标签: c# .net stream seek


【解决方案1】:

Stream 没有文件句柄,因为它是一个抽象类。实现Stream 的类可能使用文件句柄,也可能不使用文件句柄——FileStream 使用文件句柄,因为它从文件中读取数据,但例如MemoryStream 不使用。

要获取StreamFileStreamBinaryReader 的底层文件句柄(在本例中为SafeFileHandle),请使用反射访问private SafeFileHandle _handle,如下所示:

SafeFileHandle sfh = (SafeFileHandle)typeof(FileStream).GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue((FileStream)YOUR_BINARY_READER.BaseStream)

附带说明:在这种情况下,直接调用 SetFilePointer()MemoryMappedFile 都没有帮助。似乎没有快速的方法来处理我正在使用的卷上的随机磁盘访问(数百万次连续调用)。

【讨论】:

    【解决方案2】:

    由于您的BinaryReader 超过FileStream,您可以访问阅读器的BaseStream,将其转换为FileStream,然后使用其公共SafeFileHandle 属性访问句柄。像这样的:

    FileStream stream = (FileStream)(reader.BaseStream);
    //use stream.SafeFileHandle
    

    【讨论】:

      猜你喜欢
      • 2015-07-10
      • 2017-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2014-05-22
      • 2011-03-19
      相关资源
      最近更新 更多