WriteFile returns 0为字节数

WriteFile returns 0 as the number of bytes

我希望能够将 4 GB 的数据从驱动器复制到文件并恢复它。这是我的代码:

class Program
{
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr handle);

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    internal extern static IntPtr CreateFile(
       String fileName,
       int dwDesiredAccess,
       FileShare dwShareMode,
       IntPtr securityAttrs_MustBeZero,
       FileMode dwCreationDisposition,
       int dwFlagsAndAttributes,
       IntPtr hTemplateFile_MustBeZero);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool GetVolumeInformationByHandleW(
        IntPtr hDisk,
        StringBuilder volumeNameBuffer,
        int volumeNameSize,
        ref uint volumeSerialNumber,
        ref uint maximumComponentLength,
        ref uint fileSystemFlags,
        StringBuilder fileSystemNameBuffer,
        int nFileSystemNameSize);

    // Used to read in a file
    [DllImport("kernel32.dll")]
    public static extern bool ReadFile(
        IntPtr hFile,
        byte[] lpBuffer,
        uint nNumberOfBytesToRead,
        ref uint lpNumberOfBytesRead,
        IntPtr lpOverlapped);

    [DllImport("kernel32.dll")]
    public static extern bool WriteFile(
        IntPtr hFile,
        byte[] lpBuffer,
        uint nNumberOfBytesToWrite,
        out uint lpNumberOfBytesWritten,
        [In] ref NativeOverlapped lpOverlapped);


    // Used to set the offset in file to start reading
    [DllImport("kernel32.dll")]
    public static extern bool SetFilePointerEx(
        IntPtr hFile,
        long liDistanceToMove,
        ref long lpNewFilePointer,
        uint dwMoveMethod);

    internal const int GENERIC_READ = unchecked((int)0x80000000);

    internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000);

    internal const int OPEN_EXISTING = unchecked((int)3);

    static void Main(string[] args)
    {
        IntPtr hDrive = CreateFile(
            string.Format("\\.\{0}:", "G"),
            GENERIC_READ,
            FileShare.Read | FileShare.Write,
            IntPtr.Zero,
            (FileMode)OPEN_EXISTING,
            0,
            IntPtr.Zero);

        RunBackup(hDrive);

        RunRestore(hDrive);

        CloseHandle(hDrive);
    }

    private static void RunRestore(IntPtr handle)
    {
        // Set offset
        uint chunks = 100;
        uint bufferSize = 512 * chunks;
        long pt = 0;
        byte[] buffer = new byte[bufferSize];
        SetFilePointerEx(
            handle,
            0,
            ref pt,
            0);

        long oneGB = 1073741824;
        var backupSize = oneGB * 4;
        var loops = backupSize / bufferSize;

        Console.WriteLine($"Expecting {loops:N0} loops.");
        var ol = new NativeOverlapped();
        uint written = 0;
        using (var reader = new BinaryReader(File.OpenRead(@"D:\fat.backup")))
        {
            for (int i = 0; i < loops; i++)
            {
                reader.Read(buffer);

                WriteFile(
                    handle,
                    buffer,
                    bufferSize,
                    out written,
                    ref ol);

                Console.Write($"\rLoop: {i:N0}");
            }

            reader.Close();
        }
    }

    private static void RunBackup(IntPtr handle)
    {
        // Set offset
        uint chunks = 100;
        uint bufferSize = 512 * chunks;
        long pt = 0;
        byte[] buffer = new byte[bufferSize];
        SetFilePointerEx(
            handle,
            0,
            ref pt,
            0);

        long oneGB = 1073741824;
        var backupSize = oneGB * 4;
        var loops = backupSize / bufferSize;

        Console.WriteLine($"Expecting {loops:N0} loops.");

        uint read = 0;
        using (var writer = new BinaryWriter(File.OpenWrite(@"D:\fat.backup")))
        {
            for (int i = 0; i < loops; i++)
            {
                ReadFile(
                    handle,
                    buffer,
                    bufferSize,
                    ref read,
                    IntPtr.Zero);

                writer.Write(buffer);
                writer.Flush();

                Console.Write($"\rLoop: {i:N0}");
            }

            writer.Close();
        }
    }
}

备份功能似乎按预期运行。但是,在恢复部分,当程序调用WriteFile时,written变量始终为0。我做错了吗?

您对这两个例程使用相同的句柄,并且它已打开以进行读取访问。

如果您以只读方式打开一个文件,然后使用相同的句柄进行写入,很明显您将遇到问题。

解决方案

要写入磁盘,请使用 CreateFile 函数,如下所示:

[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
internal extern static IntPtr CreateFile(
    String fileName,
    FileAccess access,
    FileShare dwShareMode,
    IntPtr securityAttrs_MustBeZero,
    FileMode dwCreationDisposition,
    int dwFlagsAndAttributes,
    IntPtr hTemplateFile_MustBeZero);

IntPtr handle = CreateFile(
    string.Format("\\.\{0}:", driveLetter),
    (FileAccess)(0x40000000),
    (FileShare)0x00000001,
    IntPtr.Zero,
    FileMode.OpenOrCreate,
    0x00000080,
    IntPtr.Zero);