如何在不使用 try-catch 的情况下检查路径是否有效?

3

我想检查一个文件夹是否存在,如果不存在则创建它。但我不知道提供的路径是否有效。当路径无效时,会发生以下情况。

string path = "this is an invalid path";

if (!Directory.Exists(path))
    Directory.CreateDirectory(path); //Exception thrown here

如果您提供了无效路径,它将抛出一个DirectoryNotFoundException异常。
我该如何阻止此异常的发生?我不想使用try-catch。我希望在异常发生之前就能检测到这个异常。

7个回答

10
使用 Directory.Exists 方法来检查文件夹是否存在。
if(Directory.Exists(path))
{
  //Directory exists
}
else
{
 // doesn't exist
}

记得包含 System.IO;


2
这并不能防止异常的发生,而且尝试这样做是不好的想法。 - John Kugelman

8
您的代码失败的原因是路径无效。文档说明如下:
DirectoryNotFoundException:指定的路径无效(例如,它在未映射的驱动器上)。
事先预测是否可以创建目录是一项艰巨的工作。您需要考虑安全性、操作系统名称规则和限制、文件系统名称规则和限制以及驱动器是否已映射等问题。可能还有很多其他的问题。我不会考虑重新实现系统免费提供的功能。
无论如何,虽然您可以调用Directory.Exists,但仍需要考虑抛出异常的情况。如果在调用Directory.Exists和随后调用Directory.CreateDirectory之间文件系统发生更改,则会引发异常。例如,如果另一个进程创建了您要创建的目录。尽管这种情况不太可能发生,但完全有可能。
总之,最好的选择是捕获异常。正如众所周知的说法:“宁愿请求宽恕,而不是请求许可”。

嗨David,我不确定你会如何做到这一点?如果路径都无效,你怎么能获取父目录呢?请查看我修改后的问题。 - user1384603
4
尝试重新编码所有的检查层是毫无意义的。捕获异常即可。 - David Heffernan

3
为什么你不想捕获(特定的)异常?这被认为是一种良好的实践...无论如何,以下是我在没有使用try/catch的情况下提供的解决方案:
  1. solution:

    string path = "C:\test";
    if (!Directory.Exists(path) && path.IndexOfAny(Path.GetInvalidFileNameChars()) == -1)
    {
        Directory.CreateDirectory(path);
    }
    
  2. solution:

    string path = "C:\test";
    var canCreate = true;
    foreach (var c in path.Where(Path.GetInvalidFileNameChars().Contains))
    {
        canCreate = false;
    }
    
    if (canCreate && !Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    
  3. solution:

    if (path.Any(c => Path.GetInvalidFileNameChars().Contains(c)) && !Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    
请注意,这段代码仍然可能会失败...例如,考虑到SecurityException(你有权限在那里创建目录吗?!)
还要注意,在您使用Exists()测试之后但在调用CreateDirectory()之前,该目录仍然有(很小的)机会被另一个进程/线程创建。这是两个调用,并且它们在查询/修改文件系统时不是原子的(一起)。

在编程中使用异常来控制流程绝对不是一个好的实践方式(http://softwareengineering.stackexchange.com/a/189225/113496)。不幸的是,在某些情况下,.Net框架几乎无法避免这种情况。 - Ian Goldby
@Ian Goldby,是的,这并不是用于流控制。但他正在寻求IO和安全操作,并且在此处捕获特定异常并可能将其包装在没有异常的自有IO方法中被认为是最佳实践。无论如何,在这里工作/控制流程并不是很大,我看不出没有简单地捕获异常并以C#中典型的方式进行操作的好处,并以一种“不同”的方式进行操作而不需要这样做。他所要求的东西(据我所知)是不可能的,检查不是原子性的。那么为什么不只是捕获并继续进行真正重要的逻辑呢? - Beachwalker
@Ian Goldby,这只是简单地接受它不是原子的事实,并且查询结果是过时的,可能不正确/下一个操作的结果相同(因此需要检查目录并创建目录)。然后捕获(罕见的?)情况并处理它。这不应该在这个低级函数中对业务逻辑产生太大影响。如果异常经常发生...那么您可能会考虑为什么/您正在做什么,因为它似乎是默认情况,并且“架构”方法存在问题。 - Beachwalker
我认为从实用的角度来看,我们是达成了一致的。我只是想指出,仅仅因为.NET强制使用异常来控制流程,并不意味着这是“最佳实践”。(这更像是一种必要的恶,通过仅捕获特定的异常来稍微缓解一下。) - Ian Goldby

0

你还可以使用 Path.GetInvalidFileNameChars() 来检查所提供的目录名是否对于一个目录名是有效的:

// Directory.Exists will return false because path is not even valid
var path = "1:1 comparison?";
var firstBad = Path.GetInvalidFileNameChars().Cast<char?>()
                   .FirstOrDefault(c => path.Contains(c.Value));
if (firstBad != null)
    Console.WriteLine("Char '{0}' is invalid for a directory name", firstBad.Value);

0

试一下这个

string path = "这是一个无效的路径";

        if (Path.IsPathRooted(path)
        {
            Directory.CreateDirectory(path); 
        }

问题是如何避免在路径无效时引发异常,但是如果路径包含在GetInvalidPathChars中定义的一个或多个无效字符,则IsPathRooted会引发异常。 - Ian Goldby

0

我认为在C#中测试路径是否有效且文件存在的最简单方法,而不会引发异常,是直接调用shlwapi.dll中的非托管函数PathFileExists

[DllImport("shlwapi.dll", EntryPoint = "PathFileExistsW",  SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PathFileExists([MarshalAs(UnmanagedType.LPTStr)]string pszPath);

请注意,正如David在他的回答中所写的那样,当您尝试创建目录时仍然可能会出现异常。

-1
您可以使用单个if-else语句。
if(!Directory.Exists(path))
   Directory.CreateDirectory(path)
else
   //Show user a custom error message

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接