C# 操纵文件会阻止它们
我正在编写一个WinForms程序,它使用MEF加载程序集。这些程序集与可执行文件不在同一文件夹中。 由于需要执行一些文件维护,在加载实际WinForm之前,我在Program.cs文件中实现了一些代码,因此程序不会加载文件(即使是程序集),或者不应该加载 我正在执行两项操作: -将文件夹从一个位置移动到另一个位置 -从存档中解压缩文件并覆盖移动文件夹中的dll文件(如果存档中的文件比移动的文件新) 问题是,移动文件夹后,其中的文件被锁定,无法覆盖。我还试图通过在移动完成后处理文件来逐个移动文件 有人能解释一下为什么文件被阻止了,我怎么才能避免 谢谢C# 操纵文件会阻止它们,c#,file,mef,filestream,locked,C#,File,Mef,Filestream,Locked,我正在编写一个WinForms程序,它使用MEF加载程序集。这些程序集与可执行文件不在同一文件夹中。 由于需要执行一些文件维护,在加载实际WinForm之前,我在Program.cs文件中实现了一些代码,因此程序不会加载文件(即使是程序集),或者不应该加载 我正在执行两项操作: -将文件夹从一个位置移动到另一个位置 -从存档中解压缩文件并覆盖移动文件夹中的dll文件(如果存档中的文件比移动的文件新) 问题是,移动文件夹后,其中的文件被锁定,无法覆盖。我还试图通过在移动完成后处理文件来逐个移动文件
private static void InitializePluginsFolder()
{
if (!Directory.Exists(Paths.PluginsPath))
{
Directory.CreateDirectory(Paths.PluginsPath);
}
// Find archive that contains plugins to deploy
var assembly = Assembly.GetExecutingAssembly();
if (assembly.Location == null)
{
throw new NullReferenceException("Executing assembly is null!");
}
var currentDirectory = new FileInfo(assembly.Location).DirectoryName;
if (currentDirectory == null)
{
throw new NullReferenceException("Current folder is null!");
}
// Check if previous installation contains a "Plugins" folder
var currentPluginsPath = Path.Combine(currentDirectory, "Plugins");
if (Directory.Exists(currentPluginsPath))
{
foreach (FileInfo fi in new DirectoryInfo(currentPluginsPath).GetFiles())
{
using (FileStream sourceStream = new FileStream(fi.FullName, FileMode.Open))
{
using (FileStream destStream = new FileStream(Path.Combine(Paths.PluginsPath, fi.Name), FileMode.Create))
{
destStream.Lock(0, sourceStream.Length);
sourceStream.CopyTo(destStream);
}
}
}
Directory.Delete(currentPluginsPath, true);
}
// Then updates plugins with latest version of plugins (zipped)
var pluginsZipFilePath = Path.Combine(currentDirectory, "Plugins.zip");
// Extract content of plugins archive to a temporary folder
var tempPath = string.Format("{0}_Temp", Paths.PluginsPath);
if (Directory.Exists(tempPath))
{
Directory.Delete(tempPath, true);
}
ZipFile.ExtractToDirectory(pluginsZipFilePath, tempPath);
// Moves all plugins to appropriate folder if version is greater
// to the version in place
foreach (var fi in new DirectoryInfo(tempPath).GetFiles())
{
if (fi.Extension.ToLower() != ".dll")
{
continue;
}
var targetFile = Path.Combine(Paths.PluginsPath, fi.Name);
if (File.Exists(targetFile))
{
if (fi.GetAssemblyVersion() > new FileInfo(targetFile).GetAssemblyVersion())
{
// If version to deploy is newer than current version
// Delete current version and copy the new one
// FAILS HERE
File.Copy(fi.FullName, targetFile, true);
}
}
else
{
File.Move(fi.FullName, targetFile);
}
}
// Delete temporary folder
Directory.Delete(tempPath, true);
}
下面的语句锁定该文件
destStream.Lock(0, sourceStream.Length);
但在那之后,你还没有解锁该文件。可能这就是问题的原因。下面的语句锁定了文件
destStream.Lock(0, sourceStream.Length);
但在那之后,你还没有解锁该文件。可能这就是问题的原因。检查这部分代码中使用的
GetAssemblyVersion()
方法的实现:
if (File.Exists(targetFile))
{
if (fi.GetAssemblyVersion() > new FileInfo(targetFile).GetAssemblyVersion())
{
// If version to deploy is newer than current version
// Delete current version and copy the new one
// FAILS HERE
File.Copy(fi.FullName, targetFile, true);
}
}
fi
变量的类型为FileInfo
,GetAssemblyVersion()
看起来像一个扩展方法。您应该检查如何从文件中检索程序集版本。如果此方法加载程序集,则还应卸载程序集以释放文件
如果需要加载程序集、执行作业,然后卸载它,则单独的AppDomain
会很有用。下面是GetAssemblyVersion
方法实现:
public static Version GetAssemblyVersion(this FileInfo fi)
{
AppDomain checkFileDomain = AppDomain.CreateDomain("DomainToCheckFileVersion");
Assembly assembly = checkFileDomain.Load(new AssemblyName {CodeBase = fi.FullName});
Version fileVersion = assembly.GetName().Version;
AppDomain.Unload(checkFileDomain);
return fileVersion;
}
下面的GetAssemblyVersion()
实现可以检索程序集版本,而无需将程序集加载到AppDomain
。Thnx@usterdev获取提示。它还允许您在不使用程序集引用的情况下获取版本:
public static Version GetAssemblyVersion(this FileInfo fi)
{
return AssemblyName.GetAssemblyName(fi.FullName).Version;
}
检查此部分代码中使用的
GetAssemblyVersion()
方法的实现:
if (File.Exists(targetFile))
{
if (fi.GetAssemblyVersion() > new FileInfo(targetFile).GetAssemblyVersion())
{
// If version to deploy is newer than current version
// Delete current version and copy the new one
// FAILS HERE
File.Copy(fi.FullName, targetFile, true);
}
}
fi
变量的类型为FileInfo
,GetAssemblyVersion()
看起来像一个扩展方法。您应该检查如何从文件中检索程序集版本。如果此方法加载程序集,则还应卸载程序集以释放文件
如果需要加载程序集、执行作业,然后卸载它,则单独的AppDomain
会很有用。下面是GetAssemblyVersion
方法实现:
public static Version GetAssemblyVersion(this FileInfo fi)
{
AppDomain checkFileDomain = AppDomain.CreateDomain("DomainToCheckFileVersion");
Assembly assembly = checkFileDomain.Load(new AssemblyName {CodeBase = fi.FullName});
Version fileVersion = assembly.GetName().Version;
AppDomain.Unload(checkFileDomain);
return fileVersion;
}
下面的GetAssemblyVersion()
实现可以检索程序集版本,而无需将程序集加载到AppDomain
。Thnx@usterdev获取提示。它还允许您在不使用程序集引用的情况下获取版本:
public static Version GetAssemblyVersion(this FileInfo fi)
{
return AssemblyName.GetAssemblyName(fi.FullName).Version;
}
我会开始检查你的程序是否已经加载了程序集 两项建议: 1-在调用InitializePlugins文件夹之前调用类似的方法
static void DumpLoadedAssemblies()
{
var ads = AppDomain.CurrentDomain.GetAssemblies();
Console.WriteLine(ads.Length);
foreach (var ad in ads)
{
Console.WriteLine(ad.FullName);
// maybe this can be helpful as well
foreach (var f in ad.GetFiles())
Console.WriteLine(f.Name);
Console.WriteLine("*******");
}
}
2-在Main的第一行中,注册AssemblyLoad事件并在事件处理程序中转储加载的程序集
public static void Main()
{
AppDomain.CurrentDomain.AssemblyLoad += OnAssemlyLoad;
...
}
static void OnAssemlyLoad(object sender, AssemblyLoadEventArgs args)
{
Console.WriteLine("Assembly Loaded: " + args.LoadedAssembly.FullName);
}
我会开始检查你的程序是否已经加载了程序集 两项建议: 1-在调用InitializePlugins文件夹之前调用类似的方法
static void DumpLoadedAssemblies()
{
var ads = AppDomain.CurrentDomain.GetAssemblies();
Console.WriteLine(ads.Length);
foreach (var ad in ads)
{
Console.WriteLine(ad.FullName);
// maybe this can be helpful as well
foreach (var f in ad.GetFiles())
Console.WriteLine(f.Name);
Console.WriteLine("*******");
}
}
2-在Main的第一行中,注册AssemblyLoad事件并在事件处理程序中转储加载的程序集
public static void Main()
{
AppDomain.CurrentDomain.AssemblyLoad += OnAssemlyLoad;
...
}
static void OnAssemlyLoad(object sender, AssemblyLoadEventArgs args)
{
Console.WriteLine("Assembly Loaded: " + args.LoadedAssembly.FullName);
}
您必须确保没有将
程序集
加载到域中以从中获取版本,否则文件会被锁定
通过使用AssemblyName.GetAssemblyName()
static方法(),将加载程序集文件,读取版本,然后卸载,但不会将其添加到域中
这里是执行此操作的FileInfo
的扩展:
public static Version GetAssemblyVersion(this FileInfo fi)
{
AssemblyName an = AssemblyName.GetAssemblyName(fi.FullName);
return an.Version;
}
您必须确保没有将
程序集
加载到域中以从中获取版本,否则文件会被锁定
通过使用AssemblyName.GetAssemblyName()
static方法(),将加载程序集文件,读取版本,然后卸载,但不会将其添加到域中
这里是执行此操作的FileInfo
的扩展:
public static Version GetAssemblyVersion(this FileInfo fi)
{
AssemblyName an = AssemblyName.GetAssemblyName(fi.FullName);
return an.Version;
}
您肯定是使用AssemblyName.GetAssemblyName加载程序集的,不幸的是.NET没有在不加载程序集的情况下检查程序集元数据的常规方法。要避免这种情况,您可以:
您肯定是使用AssemblyName.GetAssemblyName加载程序集的,不幸的是.NET没有在不加载程序集的情况下检查程序集元数据的常规方法。要避免这种情况,您可以:
请分享你的代码。遗憾的是,我们甚至不能从中推测。很抱歉,我不想输入太多代码,但我想这肯定会有帮助。此方法是在主方法上调用的第一个方法。您可以验证您的程序是否正在生成锁吗?i、 e.运行一个程序创建,另一个程序提取/移动?你的错误是什么?与你的