在C# .NET 8.0/.NET 9.0中使用GetDrives()无法识别全部驱动器
问题解决与优化方案
一、外部驱动器识别问题修复
你的代码依赖DriveInfo.IsReady判断是否添加驱动器,但该属性对未就绪的外部驱动器(如刚连接未初始化、空可移动存储)会返回false,导致被跳过。更关键的是,部分系统环境下,DriveInfo.GetDrives()在存在未就绪光驱时,会遗漏枚举外部可移动驱动器,仅当光驱就绪(放入光盘)后才会完整枚举所有驱动器。
可以通过直接遍历所有可能的驱动器字母,结合Directory.Exists()判断驱动器是否存在,避免依赖DriveInfo.GetDrives()的局限性:
修改后的驱动器枚举代码
private void LoadTree() { treeView1.Nodes.Clear(); // 遍历A-Z所有可能的驱动器字母 for (char driveLetter = 'A'; driveLetter <= 'Z'; driveLetter++) { string drivePath = $"{driveLetter}:\\"; try { // 判断驱动器是否存在 if (Directory.Exists(drivePath)) { DriveInfo driveInfo = new DriveInfo(drivePath); // 格式化驱动器显示名称(带卷标) string displayName = string.IsNullOrEmpty(driveInfo.VolumeLabel) ? $"{driveLetter}:" : $"{driveLetter}: ({driveInfo.VolumeLabel})"; TreeNode driveNode = new TreeNode(displayName); treeView1.Nodes.Add(driveNode); // 加载一级目录(后续用延迟加载处理深层目录) LoadDirectoryNodes(driveNode, drivePath); } } catch { // 跳过无法访问的驱动器 continue; } } }
二、递归+延迟加载子目录实现
一次性加载所有子目录会导致界面卡顿,推荐使用延迟加载:用户展开节点时再加载对应子目录,同时通过递归获取完整路径。
步骤1:绑定TreeView展开事件
在窗体构造函数中添加事件绑定:
public YourForm() { InitializeComponent(); treeView1.BeforeExpand += TreeView1_BeforeExpand; }
步骤2:实现延迟加载逻辑
// 加载指定路径的一级目录到节点 private void LoadDirectoryNodes(TreeNode parentNode, string path) { parentNode.Nodes.Clear(); try { foreach (string dir in Directory.GetDirectories(path)) { TreeNode dirNode = new TreeNode(Path.GetFileName(dir)); // 添加虚拟节点标记需要延迟加载 dirNode.Nodes.Add(new TreeNode()); parentNode.Nodes.Add(dirNode); } } catch (UnauthorizedAccessException) { parentNode.Nodes.Add(new TreeNode("无法访问(无权限)")); } catch (Exception ex) { parentNode.Nodes.Add(new TreeNode($"错误:{ex.Message}")); } } // 展开节点时触发实际加载 private void TreeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) { TreeNode node = e.Node; // 仅处理带虚拟节点的目录 if (node.Nodes.Count == 1 && node.Nodes[0].Text == "") { node.Nodes.Clear(); string fullPath = GetFullNodePath(node); LoadDirectoryNodes(node, fullPath); } } // 递归获取节点的完整物理路径 private string GetFullNodePath(TreeNode node) { if (node.Parent == null) { // 根节点为驱动器,提取驱动器字母 return $"{node.Text[0]}:\\"; } return Path.Combine(GetFullNodePath(node.Parent), node.Text); }
说明
- 延迟加载避免了初始化时遍历全量目录,大幅提升启动速度和界面响应性;
- 递归路径处理确保能准确定位子目录的物理路径;
- 添加异常捕获,处理无权限、目录不存在等场景,避免程序崩溃。
三、完整整合代码
将上述逻辑整合后,替换原有LoadTree方法:
public partial class YourForm : Form { public YourForm() { InitializeComponent(); treeView1.BeforeExpand += TreeView1_BeforeExpand; LoadTree(); } private void LoadTree() { treeView1.Nodes.Clear(); for (char driveLetter = 'A'; driveLetter <= 'Z'; driveLetter++) { string drivePath = $"{driveLetter}:\\"; try { if (Directory.Exists(drivePath)) { DriveInfo driveInfo = new DriveInfo(drivePath); string displayName = string.IsNullOrEmpty(driveInfo.VolumeLabel) ? $"{driveLetter}:" : $"{driveLetter}: ({driveInfo.VolumeLabel})"; TreeNode driveNode = new TreeNode(displayName); treeView1.Nodes.Add(driveNode); LoadDirectoryNodes(driveNode, drivePath); } } catch { continue; } } } private void LoadDirectoryNodes(TreeNode parentNode, string path) { parentNode.Nodes.Clear(); try { foreach (string dir in Directory.GetDirectories(path)) { TreeNode dirNode = new TreeNode(Path.GetFileName(dir)); dirNode.Nodes.Add(new TreeNode()); parentNode.Nodes.Add(dirNode); } } catch (UnauthorizedAccessException) { parentNode.Nodes.Add(new TreeNode("无法访问(无权限)")); } catch (Exception ex) { parentNode.Nodes.Add(new TreeNode($"错误:{ex.Message}")); } } private void TreeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e) { TreeNode node = e.Node; if (node.Nodes.Count == 1 && node.Nodes[0].Text == "") { node.Nodes.Clear(); string fullPath = GetFullNodePath(node); LoadDirectoryNodes(node, fullPath); } } private string GetFullNodePath(TreeNode node) { if (node.Parent == null) { return $"{node.Text[0]}:\\"; } return Path.Combine(GetFullNodePath(node.Parent), node.Text); } }
内容的提问来源于stack exchange,提问作者Peter Reilly
相关产品推荐
相关产品推荐

