获取不存在的文件

时间:2014-07-08 12:05:52

标签: c# .net permissions rename filenotfoundexception

我有一个函数用于递归重命名特定文件夹中的文件,如下所示:

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

2 个答案:

答案 0 :(得分:2)

首先,您不必为此实现递归,因为Directory.EnumerateFiles()采用了一个SearchOption参数,允许您包含子目录。并不是说这会解决你的问题,但更简单的代码总是好的,所以我认为我要包含小费。

我认为Adarsha(对你的问题发表评论)正在发生一些事情。但是你怎么能利用这个优势呢?我有两种方法。可能会有更多..

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

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

  3. 祝你好运! :)

答案 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,我可以允许以多种方式访问​​文件。