Как мне прочитать диск напрямую с .Net?

Можно ли читать диск напрямую с .Net? Под напрямую я подразумеваю через устройство в обход файловой системы. Я думаю, что я бы сделал это, открыв устройство каким-то образом, например, «\Device\Ide\IdeDeviceP2T0L0-1».

Если я не могу открыть устройство с помощью .NET API, было бы полезно знать, какой Win32 API использовать.


person Darryl Braaten    schedule 01.09.2008    source источник
comment
У меня похожий вопрос, не могли бы вы мне помочь? CreateFile: «Доступ запрещен» даже с правами администратора — Win7   -  person Ali    schedule 03.01.2012


Ответы (5)


CreateFile поддерживает прямой доступ к диску. Прочтите примечания в разделе «Физические диски и тома». Вы должны иметь возможность P/Invoke вызова.

Обратите внимание, что в Vista и Server 2008 это строго ограничено.

person Mark Brackett    schedule 01.09.2008
comment
У меня похожий вопрос, не могли бы вы мне помочь? CreateFile: «Доступ запрещен» даже с правами администратора — Win7 - person Ali; 03.01.2012

Круто, спасибо, Марк, я забыл, что 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();
        }

Применяются стандартные заявления об отказе от ответственности, этот код может быть опасен для вашего здоровья.

person Darryl Braaten    schedule 01.09.2008

Мужчина. Со всей этой сортировкой и прочим, почему бы просто не написать dll на C и отказаться от .NET?

Затем вы можете p/invoke свою dll и иметь гораздо более легкое время для всего этого

person Orion Edwards    schedule 01.09.2008

Согласен с ответом Марка. Обратите внимание, что если контроль учетных записей включен (по умолчанию в Windows Vista и более поздних версиях), ваша программа должна работать с повышенными правами (с правами администратора). Если ваша программа используется только несколькими пользователями, вы можете попросить пользователя щелкнуть правой кнопкой мыши исполняемые файлы и выбрать «Запуск от имени администратора». В противном случае вы можете скомпилировать файл манифеста в программу и в манифесте указать, что программу нужно запускать с повышенными правами (ищите «requestedExecutionLevel requireAdministrator», чтобы получить дополнительную информацию).

person robbie fan    schedule 07.11.2014

В .NET 5 вы можете использовать метод FileStream для чтения файла на диске.

new FileStream(@"\\.\PhysicalDrive1", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
person OZone    schedule 16.06.2021