如何使用 .Net 直接读取磁盘?
Posted
技术标签:
【中文标题】如何使用 .Net 直接读取磁盘?【英文标题】:How do I read a disk directly with .Net? 【发布时间】:2010-09-07 11:32:57 【问题描述】:是否可以直接使用 .Net 读取磁盘?直接我的意思是通过绕过文件系统的设备。我想我会通过以某种方式打开设备“\Device\Ide\IdeDeviceP2T0L0-1”来解决这个问题。
如果我无法使用 .NET api 打开设备,知道使用哪个 Win32 API 会很有帮助。
【问题讨论】:
男人。有了所有这些编组和东西,为什么不直接用 C 编写一个 dll 而放弃 .NET 你可以 p/invoke 你的 dll 并拥有更轻松的时间 【参考方案1】:CreateFile 支持直接磁盘访问。阅读“物理磁盘和卷”下的注释。您应该能够 P/Invoke 调用。
请注意,Vista 和 Server 2008 有 severely restricted this。
【讨论】:
【参考方案2】:酷,谢谢你,马克,我忘记了 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();
标准免责声明适用,此代码可能对您的健康有害。
【讨论】:
【参考方案3】:同意马克的回答。请注意,如果启用了用户帐户控制(这是 Windows Vista 及更高版本的默认设置),则您的程序必须以提升的权限运行(具有管理权限)。如果您的程序只供少数用户使用,您可以要求用户右键单击可执行文件并选择“以管理员身份运行”。否则,您可以将清单文件编译到程序中,并在清单中指定程序需要以提升的权限运行(搜索“requestedExecutionLevel requireAdministrator”以获取更多信息)。
【讨论】:
【参考方案4】:在 .NET 5 中,您可以使用 FileStream 方法读取磁盘上的文件。
new FileStream(@"\\.\PhysicalDrive1", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
【讨论】:
以上是关于如何使用 .Net 直接读取磁盘?的主要内容,如果未能解决你的问题,请参考以下文章