C# WinForm在Documents目录写日志时出现UnauthorizedAccessException访问拒绝
问题定位与解决方案
触发当前异常的核心原因
你的代码存在两处关键逻辑错误,直接导致了权限拒绝异常:
- 路径拼接逻辑完全混乱:你之前已经通过
Path.Combine(dirPath, fileName)生成了带完整文件名的日志全路径,这个路径本身是文件地址,不是目录地址。但你在初始化StreamWriter时,又对这个文件地址执行了Path.Combine(path, filename)——根据.NET的Path.Combine规则,当第一个参数是绝对路径时,后续拼接的内容会被直接丢弃,看起来路径没变化,但本质上你完全没有搞清楚哪个变量存的是目录、哪个存的是完整文件路径。 - 最可能的异常触发点:如果你在创建目录的逻辑里,不小心把这个带文件名的全路径传给了
Directory.CreateDirectory(),系统就会在logs目录下生成一个和日志文件同名的文件夹。后续你尝试用StreamWriter往这个“同名文件夹”路径上写文件时,Windows会直接抛出权限拒绝异常——因为系统不允许向指向目录的路径写入文件流,这和你当前的异常表现完全匹配。
正确的全流程实现逻辑
你选择将日志存在用户Documents目录的思路本身完全正确:当前用户对自己的Documents目录及下属子目录天然拥有读写权限,不需要申请管理员权限,也不会和其他用户的文件产生权限冲突,完全适配多用户使用的场景。按照规范修改后的代码流程如下:
- 明确区分目录路径、文件路径的职责,避免变量混淆:
// 定义固定的应用目录、日志子目录名称 const string AppRootFolder = "DNDice"; const string LogFolder = "logs"; // 获取当前登录用户的Documents根目录 string docsRoot = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // 拼接日志所在的**目录路径**(全程不涉及文件名) string logDirFullPath = Path.Combine(docsRoot, AppRootFolder, LogFolder); // 递归创建不存在的目录 if (!Directory.Exists(logDirFullPath)) { Directory.CreateDirectory(logDirFullPath); } // 生成带时间戳的日志文件名,注意使用24小时制HH,避免12小时制hh导致同名文件 string logFileName = $"log_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt"; // 最后一步拼接得到完整的日志文件绝对路径,后续不要重复拼接 string logFileFullPath = Path.Combine(logDirFullPath, logFileName); - 直接将上面生成的完整文件路径传给StreamWriter即可,不需要额外的路径拼接操作:
// 使用using语句自动释放文件句柄,避免文件被锁定 using StreamWriter writer = new StreamWriter(logFileFullPath, append: true); // 写入日志内容 writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} 应用启动完成");
剩余异常的排查方向
如果按上面的逻辑修改后仍然抛出权限拒绝错误,可以按顺序排查:
- 手动打开
Documents\DNDice\logs目录,检查是否之前误创建了和日志文件同名的文件夹,如果有直接删除即可。 - 检查Windows Defender的“受控文件夹访问”功能是否拦截了你的程序:这类安全功能会默认拦截非白名单程序向Documents、桌面、图片库这些受保护目录写入文件,可以临时关闭功能测试,确认拦截后将你的程序加入白名单即可。
- 如果你的Documents目录被重定向到OneDrive同步路径,手动打开一次该同步目录触发文件索引刷新,排除OneDrive占位文件导致的首次写入权限异常。
内容的提问来源于stack exchange,提问作者Negomir
相关产品推荐
相关产品推荐

