文件占用异常求助:动态更新代码中File.Copy失败排查
问题描述
执行File.Copy时抛出异常:The process cannot access the file 'file path' because it is being used (unknown why)。通过资源监视器确认该DLL正被当前程序占用:
- 仅包含
File.Copy逻辑的静态版本代码在check_4_Update函数中可正常运行 - 加入其他逻辑的动态版本触发文件占用异常
- 程序通过
Class.Constructor()实例化引用了目标DLL,怀疑System.Reflection.Assembly相关代码导致文件被锁定,需定位引发占用的函数
静态版本代码
string _Source = @"path1\file.ext"; string _Target = @"path2\file.ext"; if ( File.Exists( _Source ) ) { try { File.Copy(_Source,_Target,true); return true; } catch (Exception e) { MessageBox.Show(e.Message); return false; } }
动态版本代码
private static string getBackName( string inStr, [System.Runtime.CompilerServices.CallerMemberName] string _mN = "" ) { return _mN.Split('_').Last(); } private static Int64 getFileVersion( string versionOfFile ) { if ( !File.Exists( versionOfFile )) return 0; return Int64.Parse( FileVersionInfo.GetVersionInfo( versionOfFile ).FileVersion.ToString().Replace(".","")); } private static string check_Update_dll( string _completePath ) { string _fExt = "."+getBackName(""); string[] files = Directory.GetFiles( _completePath , "*"+_fExt ); switch ( files.Length ) { case 0 : return null; case 1 : return files[files.Length-1]; default : return null; } } private static bool check_4_Update() { string _fName = (System.Reflection.Assembly.GetEntryAssembly().GetName().Name).Replace( new Class.Constructor().GetType().Name , ""); string _uPath = "\\"+getBackName("")+"\\"; string _rPath = Path.GetDirectoryName( Application.ExecutablePath ); string _fExt = Path.GetExtension( check_Update_dll( _rPath + _uPath ) ); if ( _fExt == null ) return false; string _Source = _rPath + _uPath + _fName + _fExt; Int64 _uFVer = getFileVersion( _Source ); string _Target = _rPath + "\\" + _fName + _fExt; Int64 _oFVer = getFileVersion( _Target ); if ( _oFVer >= _uFVer ) return false; if ( File.Exists( _Source ) ) { try { File.Copy(_Source,_Target,true); return true; } catch (Exception e) { MessageBox.Show(e.Message); return false; } } else { return false; } }
问题定位与解决建议
锁定来源定位
new Class.Constructor()实例化:这是核心原因。当你通过该代码创建对象时,CLR会加载对应的DLL并保持文件锁定,直到程序域卸载。静态版本未实例化该类,所以不会锁定DLL;动态版本的check_4_Update方法中调用了该代码,触发DLL加载,导致目标路径(_Target)的DLL被占用无法覆盖。FileVersionInfo.GetVersionInfo:该方法通常不会长期锁定文件,结合静态版本对比,并非主要触发因素。
解决办法
- 延迟实例化:将
new Class.Constructor()的调用移到更新操作完成之后,避免在更新前加载目标DLL。 - 无锁反射加载:若需提前访问DLL类型信息,可读取DLL字节流后通过
Assembly.Load(byte[])加载,该方式不会锁定原始文件;或使用独立AppDomain加载DLL,加载完成后卸载程序域释放文件锁。 - 重启替换:先将更新包复制到临时路径,更新完成后提示用户重启程序,在启动时替换原DLL文件。
内容的提问来源于stack exchange,提问作者beg-inner
相关产品推荐
相关产品推荐

