2

我面临的问题是我的路径字符串通过了对Path.GetInvalidPathChars()的检查,但在尝试创建目录时失败。

static void Main(string[] args)
{

    string str2 = @"C:\Temp\hjk&(*&ghj\config\";

    foreach (var character in System.IO.Path.GetInvalidPathChars())
    {
         if (str2.IndexOf(character) > -1)
         {

             Console.WriteLine("String contains invalid path character '{0}'", character);
             return;
         }
    }


    Directory.CreateDirectory(str2); //<-- Throws exception saying Invalid character.

    Console.WriteLine("Press any key..");
    Console.ReadKey();
}

知道可能是什么问题吗?

4

2 回答 2

13

在这种情况下,文档措辞中的轻微问题可能会对我们如何看待或使用 API 产生重大影响。在我们的例子中, API 的部分对我们没有多大好处。


您还没有完全阅读以下文档Path.GetInvalidPathChars()

不保证从此方法返回的数组包含文件和目录名称中无效的完整字符集。完整的无效字符集可能因文件系统而异。例如,在基于 Windows 的桌面平台上,无效路径字符可能包括 ASCII/Unicode 字符 1 到 31,以及引号 (")、小于 (<)、大于 (>)、竖线 (|)、退格 ( \b)、空 (\0) 和制表符 (\t)。

并且不要认为这Path.GetInvalidFileNameChars()会立即对您有任何好处(我们将在下面证明这是更好的选择):

不保证从此方法返回的数组包含文件和目录名称中无效的完整字符集。完整的无效字符集可能因文件系统而异。例如,在基于 Windows 的桌面平台上,无效路径字符可能包括 ASCII/Unicode 字符 1 到 31,以及引号 (")、小于 (<)、大于 (>)、竖线 (|)、退格 ( \b)、空 (\0) 和制表符 (\t)。


在这种情况下,最好try { Directory.CreateDirectory(str2); } catch (ArgumentException e) { /* Most likely the path was invalid */ } 不要手动验证路径*. 这将独立于文件系统工作。


当我尝试在我的 Windows 系统上创建您的目录时:

无效的路径字符

现在,如果我们遍历该数组中的所有字符:

foreach (char c in Path.GetInvalidPathChars())
{
    Console.WriteLine($"0x{(int)c:X4} : {c}");
}

我们得到:

0x0022 : "
0x003C : <
0x003E : >
0x007C : |
0x0000 : 
0x0001 : 
0x0002 : 
0x0003 : 
0x0004 : 
0x0005 : 
0x0006 : 
0x0007 : 
0x0008 : 
0x0009 :   
0x000A : 

0x000B : 
0x000C : 
0x000D : 
0x000E : 
0x000F : 
0x0010 : 
0x0011 : 
0x0012 : 
0x0013 : 
0x0014 : 
0x0015 : 
0x0016 : 
0x0017 : 
0x0018 : 
0x0019 : 
0x001A : 
0x001B : 
0x001C : 
0x001D : 
0x001E : 
0x001F : 

如您所见,该列表不完整。

但是:如果我们对GetInvalidFileNameChars()

foreach (char c in Path.GetInvalidFileNameChars())
{
    Console.WriteLine($"0x{(int)c:X4} : {c}");
}

我们最终得到一个不同的列表,其中包括上述所有内容,以及:

0x003A : :
0x002A : *
0x003F : ?
0x005C : \
0x002F : /

正是我们的错误消息所表明的。在这种情况下,您可能决定改用它。请记住我们上面的警告,Microsoft 不保证这两种方法的准确性。

当然,这并不完美,因为Path.GetInvalidFileNameChars()路径上使用会引发错误的失效(\在文件名中无效,但在路径中完全有效!),因此您需要对此进行更正。您可以通过忽略(至少)以下字符来做到这一点:

0x003A : :
0x005C : \

您可能还想忽略以下字符(因为有时人们使用 web/*nix 样式路径):

0x002F : /

这里要做的最后一件事是演示编写此代码的一种稍微简单的方法。(我是Code Review的常客,所以这是第二天性。)

我们可以用一种表达方式完成这一切:

System.IO.Path.GetInvalidFileNameChars().Except(new char[] { '/', '\\', ':' }).Count(c => str2.Contains(c)) > 0

使用示例:

var invalidPath = @"C:\Temp\hjk&(*&ghj\config\";
var validPath = @"C:\Temp\hjk&(&ghj\config\"; // No asterisk (*)

var invalidPathChars = System.IO.Path.GetInvalidFileNameChars().Except(new char[] { '/', '\\', ':' });

if (invalidPathChars.Count(c => invalidPath.Contains(c)) > 0)
{
    Console.WriteLine("Invalid character found.");
}
else
{
    Console.WriteLine("Free and clear.");
}

if (invalidPathChars.Count(c => validPath.Contains(c)) > 0)
{
    Console.WriteLine("Invalid character found.");
}
else
{
    Console.WriteLine("Free and clear.");
}

*:这是有争议的,如果您确定您的验证代码不会使有效路径无效,您可能需要手动验证路径。正如MikeT所说:“您应该始终尝试在获得异常之前进行验证”。您的验证代码应该与下一级验证相同或更少限制。

于 2016-11-11T17:28:33.393 回答
0

我遇到了与上述相同的问题。

由于每个子目录名称实际上都是一个文件名,因此我连接了一些在这里找到的解决方案:

string retValue = string.Empty;
var dirParts = path.Split(Path.DirectorySeparatorChar, (char)StringSplitOptions.RemoveEmptyEntries);

for (int i = 0; i < dirParts.Length; i++)
{
    if (i == 0 && Path.IsPathRooted(path))
    {
        retValue = string.Join("_", dirParts[0].Split(Path.GetInvalidPathChars()));
    } 
    else
    {
        retValue = Path.Combine(retValue, string.Join("_", dirParts[i].Split(Path.GetInvalidFileNameChars())));
    }
}

我的解决方案为问题中的给定路径返回“C:\Temp\hjk&(_&ghj\config”。

于 2022-03-05T09:20:33.100 回答