是否可以直接用.Net读取磁盘?直接我的意思是通过绕过文件系统的设备.我想我会通过某种方式打开设备来解决这个问题,例如"\ Device\Ide\IdeDeviceP2T0L0-1".
如果我无法使用.NET api打开设备,知道使用哪个Win32 API会有所帮助.
很酷,谢谢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(); } } ////// /// 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. /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. /// The maximum number of bytes to be read from the current stream. ///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(); }
标准免责声明适用,此代码可能对您的健康有害.
CreateFile支持直接磁盘访问.阅读"物理磁盘和卷"下的说明.你应该可以P/Invoke这个电话.
请注意,Vista和Server 2008 严格限制了这一点.