我有一个函数用于递归重命名特定文件夹中的文件,如下所示:
public void renameRecur(string destination)
{
DirectoryInfo dirInfo = new DirectoryInfo(destination);
//Rename each of the files
foreach(FileInfo file in dirInfo.GetFiles())
{
file.IsReadOnly = false;
/* Rename files and things... */
}
//Rename each of the directories
foreach(DirectoryInfo dir in dirInfo.EnumerateDirectories())
{
renameRecur(dir.FullName);
/* Rename directories and things... */
}
}
但是,file.IsReadOnly = false
会在随机场合抛出FileNotFoundException
例外。在查看异常提供的堆栈跟踪和信息之后,我可以使用提供的完整路径并在每次发生此异常时找到“丢失”文件。
同样,这似乎发生在随机场合,通常是当应用程序遇到处于只读模式的文件时,它会尝试使其可写。该程序并不总是每次都在同一个文件上打破。
我是该计算机的管理员,对该文件夹及其所有子文件夹和文件具有完全权限。这些文件或目录都不会被隐藏。
所以,我很好奇为什么dirInfo.GetFiles()
返回C#
认为不存在的文件。有没有人知道为什么会这样?
答案 0 :(得分:2)
首先,您不必为此实现递归,因为Directory.EnumerateFiles()
采用了一个SearchOption参数,允许您包含子目录。并不是说这会解决你的问题,但更简单的代码总是好的,所以我认为我要包含小费。
我认为Adarsha(对你的问题发表评论)正在发生一些事情。但是你怎么能利用这个优势呢?我有两种方法。可能会有更多..
实施您的逻辑,以便在出现类似此类错误的情况时优雅地恢复。最有可能通过一层或多层重试和/或重新运行。例如,如果捕获到异常,您的内部代码可以重试一次。如果它再次发生,请重新抛出并让消费代码处理它。然后让你的消费代码在一些睡眠之后重新运行整个循环,或者让你的文件系统安定下来。
使用NTFS交易。仅当您的代码在Vista / 2008或更高版本上运行时才可用。那些东西在windowsapi中,所以如果你对编组很不舒服,你可以在codeplex上使用预先写好的包装器,例如Transactional NTFS。不确定您是否可以使用它来锁定目录,但我认为您可以在提供环境事务范围时通过Txf.Directory.GetDirectory(..)
。
祝你好运! :)
答案 1 :(得分:1)
我不确定为什么DirectoryInfo会为您提供系统认为不存在的文件;但是,为了帮助您解决异常。你应该研究一下:
http://msdn.microsoft.com/en-us/library/system.io.fileinfo.exists(v=vs.110).aspx
public void renameRecur(string destination) {
DirectoryInfo dirInfo = new DirectoryInfo(destination);
foreach(FileInfo file in dirInfo.getFiles()) {
if(!file.Exists) //Try This.
continue;
file.IsReadOnly = false;
}
foreach(DirectoryInfo dir in dirInfo.EnumerateDirectories()) {
renameRecur(dir.FullName);
}
}
根据评论进行编辑:
如果您怀疑程序的另一部分已锁定文件,则应该查看此重载。
http://msdn.microsoft.com/en-us/library/5h0z48dh(v=vs.110).aspx
以下是过去的代码示例,展示了如何使用它(因为我觉得msdn缺少一个有意义的例子)
void ExternOpen(FileHeader header)
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var appDataLocation = appData + @"\" + header;
using (var fs = new FileStream(appDataLocation, FileMode.Create, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete))
using (var hs = header.GetStream())
{
hs.CopyTo(fs);
Process.Start(appDataLocation);
}
}
上面的代码获取一个通过解压缩(header.GetStream())在内存中创建的文件,然后在应用程序数据中的桌面上创建一个物理文件并打开该文件。
通过指定多个FileShares,我可以允许以多种方式访问文件。