如何从USB驱动器名称获取磁盘索引?含分区/无分区及C#清理需求
解决C#中USB驱动器名称对应diskpart磁盘编号的问题
核心思路
要把DriveInfo获取的USB驱动器名称映射到diskpart的磁盘编号,需要通过WMI查询关联驱动器、分区、物理磁盘的层级关系——DriveInfo只能获取逻辑盘符,而diskpart操作的是物理磁盘,两者需要中间的分区信息做关联。同时要单独处理无分区的USB设备:这类设备没有逻辑盘符,DriveInfo无法枚举,得直接通过WMI筛选USB类型的物理磁盘。
实现步骤
1. 关联逻辑盘符到磁盘编号(带分区的USB)
通过Win32_LogicalDiskToPartition关联逻辑盘与分区,再通过Win32_DiskDriveToDiskPartition关联分区与物理磁盘,最终获取diskpart使用的磁盘编号(即物理磁盘的Index属性)。
示例代码:
using System.Management; // 根据盘符获取对应的磁盘编号 public static int? GetDiskNumberFromDriveLetter(string driveLetter) { // 统一盘符格式为X: if (!driveLetter.EndsWith(":")) driveLetter += ":"; try { // 查询逻辑盘对应的分区 var logicalDiskQuery = new ObjectQuery($"ASSOCIATORS OF {{Win32_LogicalDisk.DeviceID='{driveLetter}'}} WHERE AssocClass=Win32_LogicalDiskToPartition"); using (var searcher = new ManagementObjectSearcher(logicalDiskQuery)) { foreach (var partitionObj in searcher.Get()) { // 查询分区对应的物理磁盘 var diskQuery = new ObjectQuery($"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{partitionObj["DeviceID"]}'}} WHERE AssocClass=Win32_DiskDriveToDiskPartition"); using (var diskSearcher = new ManagementObjectSearcher(diskQuery)) { foreach (var diskObj in diskSearcher.Get()) { return Convert.ToInt32(diskObj["Index"]); } } } } } catch (Exception ex) { Console.WriteLine($"查询磁盘编号失败: {ex.Message}"); } return null; }
2. 枚举无分区的USB物理磁盘
无分区USB没有逻辑盘符,需直接查询Win32_DiskDrive,筛选USB接口的磁盘且无关联分区的设备:
// 获取所有无分区的USB磁盘编号 public static List<int> GetUnpartitionedRemovableDisks() { var diskNumbers = new List<int>(); try { // 筛选USB接口的物理磁盘 var query = new ObjectQuery("SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'"); using (var searcher = new ManagementObjectSearcher(query)) { foreach (var diskObj in searcher.Get()) { // 检查该磁盘是否有分区 var partitionQuery = new ObjectQuery($"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{diskObj["DeviceID"]}'}} WHERE AssocClass=Win32_DiskDriveToDiskPartition"); using (var partitionSearcher = new ManagementObjectSearcher(partitionQuery)) { if (partitionSearcher.Get().Count == 0) { diskNumbers.Add(Convert.ToInt32(diskObj["Index"])); } } } } } catch (Exception ex) { Console.WriteLine($"查询无分区磁盘失败: {ex.Message}"); } return diskNumbers; }
3. 整合逻辑并执行diskpart清理
将枚举USB、映射编号、执行清理命令的逻辑整合:
using System.Diagnostics; using System.IO; public static void CleanAllUsbDevices() { // 处理带盘符的USB设备 foreach (DriveInfo drive in DriveInfo.GetDrives()) { if (drive.IsReady && drive.DriveType == DriveType.Removable) { var diskNumber = GetDiskNumberFromDriveLetter(drive.Name); if (diskNumber.HasValue) { ExecuteDiskpartClean(diskNumber.Value); } } } // 处理无分区的USB设备 var unpartitionedDisks = GetUnpartitionedRemovableDisks(); foreach (var diskNum in unpartitionedDisks) { ExecuteDiskpartClean(diskNum); } } // 执行diskpart清理命令 private static void ExecuteDiskpartClean(int diskNumber) { // 构造diskpart脚本 string scriptContent = $"select disk {diskNumber}\nclean\n"; string tempScriptPath = Path.Combine(Path.GetTempPath(), "diskpart_clean_temp.txt"); try { // 写入临时脚本文件 File.WriteAllText(tempScriptPath, scriptContent); // 启动diskpart执行脚本 var processStartInfo = new ProcessStartInfo { FileName = "diskpart.exe", Arguments = $"/s \"{tempScriptPath}\"", WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false }; using (var proc = Process.Start(processStartInfo)) { proc.WaitForExit(); if (proc.ExitCode != 0) { Console.WriteLine($"清理磁盘{diskNumber}失败,退出码: {proc.ExitCode}"); } else { Console.WriteLine($"磁盘{diskNumber}清理完成"); } } } catch (Exception ex) { Console.WriteLine($"执行diskpart失败: {ex.Message}"); } finally { // 删除临时脚本 if (File.Exists(tempScriptPath)) File.Delete(tempScriptPath); } }
关键注意事项
- 权限要求:执行diskpart需要管理员权限,程序必须以管理员身份运行,否则会操作失败。
- 数据风险:
clean命令会彻底清除磁盘所有数据,务必在代码中增加校验逻辑,确保仅清理USB设备,避免误操作本地磁盘。 - 设备兼容性:部分USB设备的
MediaType属性可能不是"Removable Media",改用InterfaceType='USB'筛选更可靠。
(无分区USB示例图:
)
内容的提问来源于stack exchange,提问作者Milan
相关产品推荐
相关产品推荐

