当前位置: 首页 > news >正文

用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);}}
}

http://www.dtcms.com/a/268759.html

相关文章:

  • Nat.C|RiNALMo:通用 RNA 语言模型新突破,3600 万序列预训练,跨家族结构预测、剪接识别与功能注释全能泛化
  • grant之后还需要跟flush privilege吗?
  • 广告系统中的RTB详解
  • IT 与动环一体化运维的技术融合实践
  • Pandas 学习(数学建模篇)
  • 牛客周赛 Round 99题解
  • C++ --- list的简单实现
  • 沙箱逃逸漏洞
  • STEP 7 MicroWIN SMART V2.2 的详细安装步骤及注意事项
  • 股票筹码分布及其数据获取
  • validate CRI v1 image API for endpoint “unix:///run/containerd/containerd.sock“
  • 代码详细注释:递归查找指定目录及其子目录中的所有BMP位图文件,并通过双重验证确保找到的文件确实是合法的BMP文件。以下是详细的功能说明:DIY机器人工房
  • Maven 私库
  • [特殊字符] Excel 读取收件人 + Outlook 批量发送带附件邮件 —— Python 自动化实战
  • pyautogui库的一些鼠标操作
  • 医学 LLM 评估相关论文笔记
  • OSPF路由过滤
  • 【python实用小脚本-130】基于 Python 的 HTML 到 Markdown 转换工具:实现高效文档格式转换
  • 深度学习7(梯度下降算法改进)
  • SLAM文献之Efficient and Consistent Bundle Adjustment on Lidar Point Clouds(BALM)
  • 安卓10.0系统修改定制化____实现自动开启 USB 调试​的步骤解析 列举常用的几种修改方法
  • 【氮化镓】​​GaN帽层对HEMTs栅极漏电机制的影响
  • LeetCode 2099.找到和最大的长度为 K 的子序列:自定义排序
  • 前端篇——HTML知识点体系
  • 解决jenkins的Exec command命令nohup java -jar不启动问题
  • 订单初版—1.分布式订单系统的简要设计文档
  • Vue 2 vs Vue 3:核心区别详解与升级指南
  • 使用ansible的角色实现批量安装nginx服务
  • ReAct (Reason and Act) OR 强化学习(Reinforcement Learning, RL)
  • [特殊字符] Python 实战 | 批量统计中文文档词频并导出 Excel