是否可以直接使用.Net读取磁盘?直接我的意思是通过绕过文件系统的设备。我想我会通过某种方式打开设备来解决这个问题,例如“\ Device \ Ide \ IdeDeviceP2T0L0-1”。
如果我无法使用.NET api打开设备,知道使用哪个Win32 API会有所帮助。
答案 0 :(得分:12)
很酷,谢谢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 :(得分:5)
CreateFile支持直接磁盘访问。阅读“物理磁盘和卷”下的说明。你应该可以P / Invoke这个电话。
请注意,Vista和Server 2008有severely restricted这个。
答案 2 :(得分:1)
曼。有了所有的编组和东西,为什么不用C编写一个dll并放弃.NET
然后你可以调用你的dll并让它更容易一切
答案 3 :(得分:0)
同意Mark的回答。请注意,如果启用了“用户帐户控制”(这是Windows Vista及更高版本上的默认设置),则您的程序必须正在升级(具有管理权限)。如果您的程序仅用于少数用户,则可以请求用户右键单击可执行文件,然后选择&#34;以管理员身份运行&#34;。否则,您可以将清单文件编译到程序中,并在清单中指定程序需要运行升级(搜索&#34; requestedExecutionLevel requireAdministrator&#34;以获取更多信息)。
答案 4 :(得分:0)
在 .NET 5 中,您可以使用 FileStream 方法读取磁盘上的文件。
new FileStream(@"\\.\PhysicalDrive1", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)