14

.Net でディスクを直接読み取ることは可能ですか? 直接とは、ファイル システムをバイパスするデバイス経由を意味します。たとえば、「\Device\Ide\IdeDeviceP2T0L0-1」という方法でデバイスを開くことで、これを行うと思います。

.NET API でデバイスを開くことができない場合、使用する Win32 API を知っていると役立ちます。

4

4 に答える 4

14

クール、ありがとうマーク、私は 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();
        }

標準の免責事項が適用されます。このコードは健康に害を及ぼす可能性があります。

于 2008-09-01T18:44:44.640 に答える
6

CreateFileは、直接ディスク アクセスをサポートしています。「物理ディスクとボリューム」の下の注意事項をお読みください。呼び出しを P/Invoke できるはずです。

Vista および Server 2008 ではこれが厳しく制限されていることに注意してください。

于 2008-09-01T17:53:24.187 に答える
0

マークの答えに同意します。ユーザー アカウント制御が有効になっている場合 (Windows Vista 以降ではデフォルト)、プログラムは管理者特権で実行されている必要があることに注意してください。プログラムを少数のユーザーのみが使用する場合は、ユーザーに実行可能ファイルを右クリックして [管理者として実行] を選択するように要求できます。それ以外の場合は、マニフェスト ファイルをプログラムにコンパイルし、マニフェストでプログラムを管理者特権で実行する必要があることを指定できます (詳細については、「requestedExecutionLevel requireAdministrator」を検索してください)。

于 2014-11-07T07:39:02.610 に答える