【问题标题】:WriteFile returns 0 as the number of bytesWriteFile 返回 0 作为字节数
【发布时间】:2021-07-31 13:14:39
【问题描述】:

我希望能够将 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();
        }
    }
}

备份功能似乎按预期工作。但是,在restore部分,当程序调用WriteFile时,written变量始终为0,是不是我做错了什么?

【问题讨论】:

标签: c# .net windows pinvoke


【解决方案1】:

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

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

解决方案

要写入磁盘,请使用 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);

【讨论】:

  • 我注释掉了第一个函数然后运行它。我通过了FileShare.Read | FileShare.Write。我猜这是导致问题的 GENERIC_READ 值。那我需要传递的值是多少?
  • @AlirezaNoori:你需要自己做一些工作。查看用于打开文件的函数的引用并传递适当的值以进行写访问(如果你想写的话)。
  • 我编辑了您的答案并添加了解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
  • 2012-04-15
  • 1970-01-01
相关资源
最近更新 更多