C# .NET Framework 4.8中File.Exists()的异常行为问题
问题根源:Windows文件系统虚拟化搞的鬼
调试和安装后行为不一致,核心原因是Windows文件系统虚拟化:
- 调试时程序运行在项目输出目录(非系统保护目录),没有虚拟化干预,
File.Exists()能准确返回真实文件状态。 - 安装后目标目录
Program Files (x86)是系统受保护目录,普通权限下的文件读写请求会被Windows偷偷重定向到用户专属的%LOCALAPPDATA%\VirtualStore\Program Files (x86)\eMA\eMA目录。你以为Program Files下没文件,但VirtualStore里早就存在该文件,所以File.Exists()返回true,还能读到内容。
另外你代码里还有两处没必要的冗余:
- 同步的
File.Exists()没必要用Task.Run包裹,纯属于浪费线程资源。 - 硬编码
SpecialFolder.ProgramFilesX86路径不靠谱,万一程序安装路径变更就会出错。
解决步骤
1. 修正路径获取逻辑
别硬编码路径,直接获取程序自身的安装目录:
// 记得引用System.Reflection命名空间 private static string AppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
2. 关闭文件虚拟化(推荐)
给项目添加应用程序清单(app.manifest),设置执行级别并禁用虚拟化:
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <!-- 如果程序不需要管理员权限,用asInvoker即可 --> <requestedExecutionLevel level="asInvoker" uiAccess="false" /> <!-- 如果必须写入Program Files,直接设为管理员权限 --> <!-- <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> --> </requestedPrivileges> </security> </trustInfo>
这样所有文件操作都会直接作用于真实的安装目录,不会再被重定向。
3. 简化冗余的异步代码
同步方法没必要套Task.Run,直接修改:
private static bool CheckIfVersionJSONFileExists() { string fileName = Path.Combine(AppPath, "version.json"); return File.Exists(fileName); }
调用的时候直接去掉await即可。
验证方式
打开%LOCALAPPDATA%\VirtualStore\Program Files (x86)\eMA\eMA目录,你会发现这里藏着你读到的version.json文件。按上面的方法修改后,文件就会直接出现在真实的安装目录里了。
内容的提问来源于stack exchange,提问作者joseenrique61
相关产品推荐
相关产品推荐

