用c#一款U盘批量按扇区复制的程序
1.运行界面
2.代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;//#define SECTOR_SIZE 512namespace USBDuplicator
{class Program{// 导入Windows API函数[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]static extern IntPtr CreateFile(string lpFileName,uint dwDesiredAccess,uint dwShareMode,IntPtr lpSecurityAttributes,uint dwCreationDisposition,uint dwFlagsAndAttributes,IntPtr hTemplateFile);[DllImport("kernel32.dll", SetLastError = true)]static extern bool ReadFile(IntPtr hFile,byte[] lpBuffer,uint nNumberOfBytesToRead,out uint lpNumberOfBytesRead,IntPtr lpOverlapped);[DllImport("kernel32.dll", SetLastError = true)]static extern bool WriteFile(IntPtr hFile,byte[] lpBuffer,uint nNumberOfBytesToWrite,out uint lpNumberOfBytesWritten,IntPtr lpOverlapped);[DllImport("kernel32.dll", SetLastError = true)]static extern bool CloseHandle(IntPtr hObject);[DllImport("kernel32.dll", SetLastError = true)]static extern bool DeviceIoControl(IntPtr hDevice,uint dwIoControlCode,IntPtr lpInBuffer,uint nInBufferSize,IntPtr lpOutBuffer,uint nOutBufferSize,out uint lpBytesReturned,IntPtr lpOverlapped);// 常量定义const uint GENERIC_READ = 0x80000000;const uint GENERIC_WRITE = 0x40000000;const uint FILE_SHARE_READ = 0x00000001;const uint FILE_SHARE_WRITE = 0x00000002;const uint OPEN_EXISTING = 3;const uint FILE_FLAG_NO_BUFFERING = 0x20000000;const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;const uint IOCTL_DISK_GET_LENGTH_INFO = 0x0007405C;const uint SECTOR_SIZE = 512;static void Main(string[] args){Console.WriteLine("=== U盘扇区级批量复制工具 ===");try{// 1. 检测所有可移动磁盘var drives = GetRemovableDrives();if (drives.Count == 0){Console.WriteLine("未检测到可移动磁盘!");return;}// 2. 显示磁盘列表Console.WriteLine("\n检测到的可移动磁盘:");for (int i = 0; i < drives.Count; i++){Console.WriteLine($"[{i}] {drives[i].Name} ({drives[i].SizeGB:0.00} GB)");}// 3. 选择源盘Console.Write("\n选择源盘编号: ");string? sourceInput = Console.ReadLine();if (string.IsNullOrEmpty(sourceInput)){Console.WriteLine("未输入源盘编号!");return;}if (!int.TryParse(sourceInput, out int sourceIndex)){Console.WriteLine("无效的源盘选择");return;}if (sourceIndex < 0 || sourceIndex >= drives.Count){Console.WriteLine("无效的源盘选择");return;}// 4. 选择目标盘(可多选)Console.Write("选择目标盘编号(用逗号分隔): ");string? targetInput = Console.ReadLine();if (string.IsNullOrEmpty(targetInput)){Console.WriteLine("未输入目标盘编号!");return;}var targetIndices = targetInput.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(s => int.TryParse(s.Trim(), out int num) ? num : -1).Where(i => i >= 0).Distinct().ToList();// 5. 验证选择if (targetIndices.Contains(sourceIndex)){Console.WriteLine("目标盘不能包含源盘");return;}var sourceDrive = drives[sourceIndex];var targetDrives = targetIndices.Where(i => i < drives.Count).Select(i => drives[i]).ToList();if (targetDrives.Count == 0){Console.WriteLine("未选择有效的目标盘");return;}// 6. 确认操作Console.WriteLine($"\n即将复制:{sourceDrive.Name} -> {string.Join(", ", targetDrives.Select(d => d.Name))}");Console.Write("确认操作?(y/n): ");if (Console.ReadLine()?.ToLower() != "y")return;// 7. 执行批量复制BatchSectorCopy(sourceDrive, targetDrives);}catch (Exception ex){Console.WriteLine($"错误: {ex.Message}");}finally{Console.WriteLine("\n按任意键退出...");Console.ReadKey();}}// 获取所有可移动磁盘信息static List<DriveInfoEx> GetRemovableDrives(){return DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Removable && d.IsReady).Select(d => new DriveInfoEx(d)).ToList();}// 批量扇区复制核心方法static void BatchSectorCopy(DriveInfoEx source, List<DriveInfoEx> targets){const int SECTOR_SIZE = 512; // 标准扇区大小const int BUFFER_SECTORS = 2048; // 每次读取的扇区数(1MB缓冲)byte[] buffer = new byte[BUFFER_SECTORS * SECTOR_SIZE];// 打开源盘IntPtr sourceHandle = OpenPhysicalDrive(source.Name, true);if (sourceHandle == IntPtr.Zero || sourceHandle.ToInt32() == -1){throw new Win32Exception(Marshal.GetLastWin32Error());}try{// 获取源盘总扇区数long totalSectors = GetDiskSizeInSectors(sourceHandle);Console.WriteLine($"\n开始复制: {source.Name} ({totalSectors} 扇区)");// 打开所有目标盘var targetHandles = new List<IntPtr>();foreach (var t in targets){Console.WriteLine($"准备目标盘: {t.Name}");IntPtr targetHandle = OpenPhysicalDrive(t.Name, false);if (targetHandle == IntPtr.Zero || targetHandle.ToInt32() == -1){Console.WriteLine($"无法打开目标盘 {t.Name},错误代码: {Marshal.GetLastWin32Error()}");continue;}targetHandles.Add(targetHandle);}if (targetHandles.Count == 0){Console.WriteLine("没有有效的目标盘可写入");return;}try{// 复制进度跟踪long sectorsCopied = 0;var timer = new System.Diagnostics.Stopwatch();timer.Start();// 按扇区循环复制while (sectorsCopied < totalSectors){// 计算本次读取扇区数int sectorsToRead = (int)Math.Min(BUFFER_SECTORS,totalSectors - sectorsCopied);// 从源盘读取if (!ReadSectors(sourceHandle, buffer, sectorsCopied, sectorsToRead)){throw new Win32Exception(Marshal.GetLastWin32Error());}// 写入所有目标盘foreach (var targetHandle in targetHandles){if (!WriteSectors(targetHandle, buffer, sectorsCopied, sectorsToRead)){Console.WriteLine($"写入目标盘失败,错误代码: {Marshal.GetLastWin32Error()}");}}// 更新进度sectorsCopied += sectorsToRead;double progress = (double)sectorsCopied / totalSectors * 100;double speedMB = (sectorsCopied * SECTOR_SIZE) /(timer.Elapsed.TotalSeconds * 1024 * 1024);Console.Write($"\r进度: {progress:0.00}% | 速度: {speedMB:0.0} MB/s");}timer.Stop();Console.WriteLine($"\n复制完成! 耗时: {timer.Elapsed.TotalSeconds:0.0}秒");}finally{// 关闭所有目标盘句柄foreach (var handle in targetHandles){if (handle != IntPtr.Zero)CloseHandle(handle);}}}finally{// 关闭源盘句柄if (sourceHandle != IntPtr.Zero)CloseHandle(sourceHandle);}}// 打开物理驱动器static IntPtr OpenPhysicalDrive(string drivePath, bool readOnly){string physicalPath = @"\\.\" + drivePath.TrimEnd('\\');uint access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);IntPtr handle = CreateFile(physicalPath,access,FILE_SHARE_READ | FILE_SHARE_WRITE,IntPtr.Zero,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,IntPtr.Zero);return handle;}// 获取磁盘扇区总数static long GetDiskSizeInSectors(IntPtr driveHandle){byte[] outBuffer = new byte[8];GCHandle pinnedBuffer = GCHandle.Alloc(outBuffer, GCHandleType.Pinned);IntPtr bufferPtr = pinnedBuffer.AddrOfPinnedObject();try{uint bytesReturned;if (!DeviceIoControl(driveHandle,IOCTL_DISK_GET_LENGTH_INFO,IntPtr.Zero,0,bufferPtr,(uint)outBuffer.Length,out bytesReturned,IntPtr.Zero)){throw new Win32Exception(Marshal.GetLastWin32Error());}long totalBytes = BitConverter.ToInt64(outBuffer, 0);return totalBytes / SECTOR_SIZE; // 转换为扇区数}finally{pinnedBuffer.Free();}}// 读取扇区数据static bool ReadSectors(IntPtr driveHandle, byte[] buffer, long startSector, int sectorCount){uint bytesRead;long offset = startSector * 512;// 设置文件指针if (SetFilePointer(driveHandle, offset) != offset)return false;return ReadFile(driveHandle, buffer, (uint)(sectorCount * 512),out bytesRead, IntPtr.Zero);}// 写入扇区数据static bool WriteSectors(IntPtr driveHandle, byte[] buffer, long startSector, int sectorCount){uint bytesWritten;long offset = startSector * 512;// 设置文件指针if (SetFilePointer(driveHandle, offset) != offset)return false;return WriteFile(driveHandle, buffer, (uint)(sectorCount * 512),out bytesWritten, IntPtr.Zero);}// 设置文件指针(简化版)static long SetFilePointer(IntPtr hFile, long distance){const uint FILE_BEGIN = 0;int low = (int)(distance & 0xFFFFFFFF);int high = (int)(distance >> 32);return SetFilePointer(hFile, low, ref high, FILE_BEGIN);}[DllImport("kernel32.dll", SetLastError = true)]static extern int SetFilePointer(IntPtr hFile,int lDistanceToMove,ref int lpDistanceToMoveHigh,uint dwMoveMethod);}// 扩展的驱动器信息类class DriveInfoEx{public string Name { get; }public double SizeGB { get; }public DriveInfoEx(DriveInfo drive){Name = drive.Name.Substring(0, 2); // 获取盘符 (如 "D:")SizeGB = drive.TotalSize / (1024.0 * 1024 * 1024);}}
}