重命名目录锁定重命名目录我第二次要重命名

Posted

技术标签:

【中文标题】重命名目录锁定重命名目录我第二次要重命名【英文标题】:Renaming a directory locks renamed dir the second time I want to rename 【发布时间】:2011-07-15 21:19:43 【问题描述】:

我多次重命名目录时遇到问题,它似乎锁定了文件。

// e comes from a objectListView item
DirectoryInfo di = (DirectoryInfo)e.RowObject;
DirectoryInfo parent = Directory.GetParent(di.FullName);
String newPath = Path.Combine(parent.FullName, e.NewValue.ToString());

// rename to some temp name, to help change lower and uppercast names
di.MoveTo(newPath + "__renameTemp__");
di.MoveTo(newPath);

// Trying to cleanup to prevent directory locking, doesn't work...
di = null;
parent = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

非常感谢任何帮助,因为第一次重命名工作正常,但是当尝试对重命名的文件夹进行新的重命名时,它会引发异常:

进程无法访问文件 因为它正在被另一个人使用 过程。第一次机会例外 类型“System.IO.IOException”发生 在 mscorlib.dll 中

所以第一次重命名该文件夹有效,第二次抛出异常,我猜应用程序锁定了新文件夹,但如何解决它?我应该可以重命名一个文件夹两次吧?

【问题讨论】:

当您运行此程序并获得异常时,您能否告诉我们 e.RowObject 和 e.NewValue 的值是什么? e.NewValue 是编辑单元格后返回的值,因此任何字符串都可以。 RowObject 是一个 DirectoryInfo,它作为一个对象被存储为一个转换回 DirectoryInfo 的对象,这就是 ObjectListView 控件存储它的值的​​方式。我认为重点应该放在持有路径引用的对象的锁定和处置上。我检查了所有其他值,它们返回正常。 你试过Directory.Move(di.FullName, newPath); 是的,刚刚做了,同样的结果,第一次重命名例程工作得很好,第二次我调用代码是一部分的处理程序,它抛出正在使用的异常。没有病毒扫描程序或什么都没有,关闭并再次启动程序允许我再次重命名它,但只有 1 次。 看看我更新的答案。 Aidiakapi 的建议很好,只是您可能没有从代码中删除所有出现的 DirectoryInfo。 【参考方案1】:

简介

为了重现您的问题,我创建了以下方法:

private static string RenameFolder(string path, string newFolderName)

    DirectoryInfo di = new DirectoryInfo(path);
    DirectoryInfo parent = Directory.GetParent(di.FullName);
    String newPath = Path.Combine(parent.FullName, newFolderName);

    // rename to some temp name, to help change lower and uppercast names
    di.MoveTo(newPath + "__renameTemp__");
    di.MoveTo(newPath);

    return di.FullName;

当我这样称呼它时,它可以工作:

var path = @"C:\Temp\test";
var newPath = RenameFolder(path, "TESt");
newPath = RenameFolder(path, "Test1");

当我像下面这样调用它时,它不起作用:

var path = @"C:\Temp\test";
var newPath = RenameFolder(path, "TESt");
newPath = RenameFolder(newPath, "Test1");

这两个调用之间的唯一区别是,在第一个版本中,我传入了原始名称,即所有内容都是小写的。在第二种情况下,我提供了新名称,即除了最后一个字母之外的所有内容都是大写的。即使在两次调用 RenameFolder 之间睡 20 秒也不会改变这一点。奇怪!

解决方案

如果我像这样实现RenameFolder它适用于两种情况

private static string RenameFolder(string path, string newFolderName)

    String newPath = Path.Combine(Path.GetDirectoryName(path), newFolderName);

    // rename to some temp name, to help change lower and uppercast names
    Directory.Move(path, newPath + "__renameTemp__");
    Directory.Move(newPath + "__renameTemp__", newPath);

    return newPath;

不知何故,DirectoryInfo 似乎在路径上有一个区分大小写的锁。

说明 我没有,也许对DirectoryInfo 的内部方式有更深入了解的人可以对这种奇怪的行为有所了解。

重点 如果您不知道自己在做什么,请不要使用GC.Collect!通常,您不需要调用此方法。

【讨论】:

很好,不要不要使用 GC.Collect,除非你知道你在做什么。就我而言,我猜该目录正在被另一个程序使用?在再次使用之前尝试关闭它。 我知道 GC 需要谨慎使用,但我没有想法。我的机器上没有病毒扫描程序或类似的东西。不管我在哪个目录运行它,每次都没有运气,重新启动应用程序,再次运行。 @JHN:你有没有试过我的建议在两个动作之间睡觉? @Daniel,是的,刚刚做了一个 System.Threading.Thread.Sleep(500);和相同的行为。我将尝试将其取出到一个简单的应用程序中,看看是否仍然发生锁定。 @JHN:只是为了澄清一点:上面代码中对MoveTo 的第二次调用是否会引发异常?还是您发布的完整代码第一次运行良好但第二次运行良好?【参考方案2】:

我之前的答案是错误的。如 cmets 中所述,MoveTo() 方法会更新 DirectoryInfo 对象以表示新路径,但没有明确记录。

正如 Daniel Hilgarth 在他的回答中指出的那样,问题可能出在其他地方。您可能需要添加逻辑来检查目录何时可以再次访问。

【讨论】:

-1:你回答的第一句话是错误的。 DirectoryInfo 实例被更新以反映调用 MoveTo 后的新路径 @Daniel:有趣,这是一个未记录的副作用。 可能没有记录,但不是很明显吗? DirectoryInfo 不是静态类。如果您要实现这样的类,您不会同样实现它吗?其他任何事情都是不直观的。 不,我使用的是 DirectoryInfo.moveTo,因此在第一次 tempName 重命名后,全名将存储回 DirectoryInfo 并且连续重命名工作正常。尝试重命名新重命名的文件夹是问题所在。我还吐出了中间的所有全名,第一次运行它的行为符合预期。 @Steven:只有在 DirectoryInfo 是不可变的情况下才有意义,这确实是值得讨论的一点。【参考方案3】:

获取进程监视器的副本,并在重命名后查看究竟是什么锁定了该目录:

http://technet.microsoft.com/en-us/sysinternals/bb896645

【讨论】:

+1 表示我可能误解了他的问题 我不知道如何从有助于解决此问题的过程资源管理器中获取有意义的信息。我过滤应用程序,我看到线程开始和退出,但没有特定于重命名。

以上是关于重命名目录锁定重命名目录我第二次要重命名的主要内容,如果未能解决你的问题,请参考以下文章

EBUSY:资源繁忙或锁定,重命名。

linux 下对文件重命名

linux基础问题 创建目录 拷贝 重命名 设置权限

如何重命名 .git 目录?

在linux下复制文件到另外一个目录并且重命名的具体操作如何?

DOS按规则批量重命名所有(子)目录下文件