Dot-Net

如何使用 .Net 直接讀取磁碟?

  • June 16, 2021

是否可以直接使用.Net 讀取磁碟?直接我的意思是通過繞過文件系統的設備。我想我會通過以某種方式打開設備“\Device\Ide\IdeDeviceP2T0L0-1”來解決這個問題。

如果我無法使用 .NET api 打開設備,知道使用哪個 Win32 API 會很有幫助。

CreateFile支持直接磁碟訪問。閱讀“物理磁碟和卷”下的註釋。您應該能夠 P/Invoke 呼叫。

請注意,Vista 和 Server 2008對此進行了嚴格限制

酷,謝謝馬克,我忘記了 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();
       }

適用標準免責聲明,此程式碼可能對您的健康有害。

引用自:https://stackoverflow.com/questions/38190