获取不存在的文件
Posted
技术标签:
【中文标题】获取不存在的文件【英文标题】:Fetching files that don't exist 【发布时间】:2014-08-29 03:59:07 【问题描述】:我有一个函数用于递归地重命名特定文件夹中的文件,如下所示:
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#
认为不存在的文件。有没有人知道为什么会这样?
【问题讨论】:
那些文件被隐藏了吗? @NikhilAgrawal 不,这些文件都没有被隐藏。 还有其他程序写入这些文件吗?如果是这样,操作系统将(取决于程序)删除旧文件并创建一个新文件。所以我们可以有一个竞争条件,当你的循环尝试访问文件时,它不存在,但你稍后会找到它。 @Adarsha 好点,但不,我的程序是唯一访问这些文件的程序,它在单个线程上这样做。 在开始处理文件/子目录之前,您可以在***目录上使用 FileSystemWatcher;使用它的事件来监视任何被重命名或删除的文件。这可能会揭示正在发生的事情,或者至少是没有发生的事情。请务必正确设置它,以便同时监视子目录中的文件。 【参考方案1】:首先,您不必为此实现递归,因为Directory.EnumerateFiles()
采用允许您包含子目录的 SearchOption 参数。并不是说这会解决您的问题,但更简单的代码总是好的,所以我想我会包含提示。
我认为 Adarsha(对您的问题发表评论)正在做某事。但是你怎么能利用它来发挥你的优势呢?我有两种方法。可能还有更多..
实施您的逻辑,以便在发生此类不良事件时能够正常恢复。很可能通过一层或多层重试和/或重新运行。例如,如果捕获到异常,您的内部代码可以重试一次。如果再次发生,重新抛出并让消费代码处理它。然后让你的消费代码在睡眠一段时间后重新运行整个循环,或者让你的文件系统稳定下来。
使用 NTFS 事务。仅当您的代码将在 Vista/2008 或更高版本上运行时才可用。这些东西在 windowsapi 中,所以如果你对编组感到不舒服,你可以在 codeplex 上使用预先编写的包装器,例如Transactional NTFS。不确定您是否可以使用它来锁定您的目录,但我认为您可以通过Txf.Directory.GetDirectory(..)
同时提供您的环境事务范围。
祝你好运! :)
【讨论】:
我会研究这些建议。谢谢!【参考方案2】:我不太确定为什么 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);
基于 cmets 编辑:
如果您怀疑程序的另一部分已锁定文件,则应查看此重载。
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())得到一个在内存中创建的文件,然后在应用Data的桌面上创建一个物理文件并打开该文件。
通过指定多个文件共享,我可以允许以多种方式访问文件。
【讨论】:
理论上听起来不错,通常我会检查文件是否存在,但我需要处理每个文件,并且不能冒险 C# 跳过实际存在的文件。 好的,在这种情况下,我建议您再次运行该程序;但是,这一次它抛出异常时存储文件的名称。然后去看看它抛出错误的实际文件。可能是该文件被隐藏,被另一个程序或其他东西修改。查看哪些文件抛出了这个异常可能是调试它的第一步。 朝着正确方向迈出的一大步!我的文件没有隐藏,但您可能对文件锁定是正确的。我的程序确实打开了要写入的文件(未包含在我的代码示例中),如果它在此过程中的任何时候退出,则可能不会释放锁。你知道File.Move()
是否试图锁定文件吗?还是file.IsReadOnly = true|false
?以上是关于获取不存在的文件的主要内容,如果未能解决你的问题,请参考以下文章
在可可中使用 nsfilesustem 获取文件属性不存在此类文件
CoreData, NSManagedObject 获取或创建(如果不存在)