【问题标题】:How do I read a disk directly with .Net?如何使用 .Net 直接读取磁盘?
【发布时间】:2010-09-07 11:32:57
【问题描述】:

是否可以直接使用 .Net 读取磁盘?直接我的意思是通过绕过文件系统的设备。我想我会通过以某种方式打开设备“\Device\Ide\IdeDeviceP2T0L0-1”来解决这个问题。

如果我无法使用 .NET api 打开设备,知道使用哪个 Win32 API 会很有帮助。

【问题讨论】:

  • 男人。有了所有这些编组和东西,为什么不直接用 C 编写一个 dll 而放弃 .NET 你可以 p/invoke 你的 dll 并拥有更轻松的时间

标签: .net winapi disk


【解决方案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)
        

        【讨论】:

          猜你喜欢
          • 2014-11-23
          • 2015-12-18
          • 2014-06-13
          • 2016-12-10
          • 2011-02-20
          • 2011-02-06
          • 1970-01-01
          • 1970-01-01
          • 2014-04-05
          相关资源
          最近更新 更多