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