获取不存在的文件

本文关键字:文件 不存在 获取 | 更新日期: 2023-09-27 18:12:01

我有一个函数,我用它来递归地重命名特定文件夹中的文件,像这样:

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#认为不存在的文件。有人知道为什么会这样吗?

获取不存在的文件

首先,您不必为此实现递归,因为Directory.EnumerateFiles()接受一个SearchOption参数,允许您包含子目录。这并不能解决您的问题,但是更简单的代码总是好的,所以我认为我应该包括这个技巧。

我认为Adarsha(评论你的问题)说到点子上了。但你如何利用这一点呢?我有两个想法。

  1. 实现您的逻辑,以便在发生类似这样的错误时优雅地恢复。最可能的是通过一个或多个重试和/或重新运行层。例如,如果捕获异常,内部代码可以重试一次。如果再次发生,重新抛出并让消费代码处理它。然后让你的消费代码在一些睡眠或其他什么之后重新运行整个循环,让你的文件系统安定下来。

  2. 使用NTFS事务。仅当您的代码将在Vista/2008或更高版本上运行时可用。这些东西都在windowsapi中,所以如果你不喜欢编组,你可以使用一个预先编写的包装器,比如codeplex上的Transactional NTFS。不确定你是否可以使用它来锁定你的目录,但我认为你可以通过Txf.Directory.GetDirectory(..)来提供你的环境事务范围。

祝你好运!:)

我不太确定为什么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())在内存中创建一个文件,然后在应用程序Data的桌面上创建一个物理文件,并打开该文件。

通过指定多个文件共享,我可以允许以多种方式访问文件。