2008-09-01 64 views
11

是否可以使用.Net直接读取磁盘?我直接指的是通过绕过文件系统的设备。我想我会通过打开设备的方式去解决这个问题,例如“\ Device \ Ide \ IdeDeviceP2T0L0-1”。如何直接使用.Net读取磁盘?

如果我不能用.NET api打开设备,知道使用哪个Win32 API会有帮助。

+0

我有一个类似的问题,你能帮我吗? [CreateFile:“访问被拒绝”即使有管理员权限 - Win7](http://stackoverflow.com/q/8694713/341970) – Ali 2012-01-03 09:56:00

回答

4

CreateFile支持直接磁盘访问。阅读“物理磁盘和卷”下的说明。您应该能够P /调用该呼叫。

请注意,Vista和Server 2008有severely restricted这个。

+0

我有一个类似的问题,你能帮我吗? [CreateFile:“访问被拒绝”,即使有管理员权限 - Win7](http://stackoverflow.com/q/8694713/341970) – Ali 2012-01-03 09:56:19

8

很酷,谢谢Mark,我忘记了CreateFile也会打开一些东西。我在看卷管理API,并没有看到如何打开东西。

这是一个包装的小类。将SafeFileHandle传递给FileStream也可能是正确的。

using System; 
using System.Runtime.InteropServices; 
using System.IO; 
using Microsoft.Win32.SafeHandles; 

namespace ReadFromDevice 
{ 
    public class DeviceStream : Stream, IDisposable 
    { 
     public const short FILE_ATTRIBUTE_NORMAL = 0x80; 
     public const short INVALID_HANDLE_VALUE = -1; 
     public const uint GENERIC_READ = 0x80000000; 
     public const uint GENERIC_WRITE = 0x40000000; 
     public const uint CREATE_NEW = 1; 
     public const uint CREATE_ALWAYS = 2; 
     public const uint OPEN_EXISTING = 3; 

     // Use interop to call the CreateFile function. 
     // For more information about CreateFile, 
     // see the unmanaged MSDN reference library. 
     [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
     private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, 
      uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, 
      uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     private static extern bool ReadFile(
      IntPtr hFile,      // handle to file 
      byte[] lpBuffer,    // data buffer 
      int nNumberOfBytesToRead,  // number of bytes to read 
      ref int lpNumberOfBytesRead, // number of bytes read 
      IntPtr lpOverlapped 
      // 
      // ref OVERLAPPED lpOverlapped  // overlapped buffer 
      ); 

     private SafeFileHandle handleValue = null; 
     private FileStream _fs = null; 

     public DeviceStream(string device) 
     { 
      Load(device); 
     } 

     private void Load(string Path) 
     { 
      if (string.IsNullOrEmpty(Path)) 
      { 
       throw new ArgumentNullException("Path"); 
      } 

      // Try to open the file. 
      IntPtr ptr = CreateFile(Path, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); 

      handleValue = new SafeFileHandle(ptr, true); 
      _fs = new FileStream(handleValue, FileAccess.Read); 

      // If the handle is invalid, 
      // get the last Win32 error 
      // and throw a Win32Exception. 
      if (handleValue.IsInvalid) 
      { 
       Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      } 
     } 

     public override bool CanRead 
     { 
      get { return true; } 
     } 

     public override bool CanSeek 
     { 
      get { return false; } 
     } 

     public override bool CanWrite 
     { 
      get { return false; } 
     } 

     public override void Flush() 
     { 
      return; 
     } 

     public override long Length 
     { 
      get { return -1; } 
     } 

     public override long Position 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 
     /// <summary> 
     /// </summary> 
     /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and 
     /// (offset + count - 1) replaced by the bytes read from the current source. </param> 
     /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream. </param> 
     /// <param name="count">The maximum number of bytes to be read from the current stream.</param> 
     /// <returns></returns> 
     public override int Read(byte[] buffer, int offset, int count) 
     { 
      int BytesRead =0; 
      var BufBytes = new byte[count]; 
      if (!ReadFile(handleValue.DangerousGetHandle(), BufBytes, count, ref BytesRead, IntPtr.Zero)) 
      { 
       Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      } 
      for (int i = 0; i < BytesRead; i++) 
      { 
       buffer[offset + i] = BufBytes[i]; 
      } 
      return BytesRead; 
     } 
     public override int ReadByte() 
     { 
      int BytesRead = 0; 
      var lpBuffer = new byte[1]; 
      if (!ReadFile(
      handleValue.DangerousGetHandle(),      // handle to file 
      lpBuffer,    // data buffer 
      1,  // number of bytes to read 
      ref BytesRead, // number of bytes read 
      IntPtr.Zero 
      )) 
      { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); ;} 
      return lpBuffer[0]; 
     } 

     public override long Seek(long offset, SeekOrigin origin) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void SetLength(long value) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void Write(byte[] buffer, int offset, int count) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void Close() 
     { 
      handleValue.Close(); 
      handleValue.Dispose(); 
      handleValue = null; 
      base.Close(); 
     } 
     private bool disposed = false; 

     new void Dispose() 
     { 
      Dispose(true); 
      base.Dispose(); 
      GC.SuppressFinalize(this); 
     } 

     private new void Dispose(bool disposing) 
     { 
      // Check to see if Dispose has already been called. 
      if (!this.disposed) 
      { 
       if (disposing) 
       { 
        if (handleValue != null) 
        { 
         _fs.Dispose(); 
         handleValue.Close(); 
         handleValue.Dispose(); 
         handleValue = null; 
        } 
       } 
       // Note disposing has been done. 
       disposed = true; 

      } 
     } 

    } 
} 

而使用类

static void Main(string[] args) 
     { 
      var reader = new BinaryReader(new DeviceStream(@"\\.\PhysicalDrive3")); 
      var writer = new BinaryWriter(new FileStream(@"g:\test.dat", FileMode.Create)); 
      var buffer = new byte[MB]; 
      int count; 
      int loopcount=0; 
      try{ 
       while((count=reader.Read(buffer,0,MB))>0) 
       { 
        writer.Write(buffer,0,count); 
        System.Console.Write('.'); 
        if(loopcount%100==0) 
        { 
         System.Console.WriteLine(); 
         System.Console.WriteLine("100MB written"); 
         writer.Flush(); 
        } 
        loopcount++; 
       } 
      } 
      catch(Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
      reader.Close(); 
      writer.Flush(); 
      writer.Close(); 
     } 

标准的声明的例子,这些代码可能会危害您的健康。

1

男人。与所有的编组的东西,为什么不只是写在C DLL和.NET放弃

然后你可以P /调用你的DLL和对它有更容易的时间都

0

同意与马克的回答。请注意,如果启用了用户帐户控制(这是Windows Vista和更高版本的默认设置),则您的程序必须运行提升(具有管理权限)。如果您的程序仅用于少数用户,则可以请求用户右键单击可执行文件并选择“以管理员身份运行”。否则,可以将清单文件编译到程序中,并在清单中指定该程序需要运行提升(搜索“requestedExecutionLevel requireAdministrator”以获取更多信息)。