是什么原因导致Directory.GetFiles出现此ArgumentException

本文关键字:ArgumentException GetFiles Directory 是什么 | 更新日期: 2023-09-27 18:27:51

以下代码段已经运行了好几个星期,但今天我遇到了这个异常:

System.ArgumentException: Illegal characters in path.
    at System.IO.Path.CheckInvalidPathChars(String path)
    at System.IO.Path.InternalCombine(String path1, String path2)
    at System.IO.FileSystemEnumerableIterator`1.GetFullSearchString(String fullPath, String searchPattern)
    at System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler)
    at System.IO.DirectoryInfo.InternalGetFiles(String searchPattern, SearchOption searchOption)
    at System.IO.DirectoryInfo.GetFiles(String searchPattern)
    at MyCompany.GetSendDefinition(String deviceId)
    ...

这是代码

public SendDefinition GetSendDefinition(string deviceId)
{
    Logger.Debug("Definition for '{0}'" deviceId);
    string storePath = Path.Combine(_serviceFolder, TcpFolder);
    var info = new DirectoryInfo(storePath);
    if (!info.Exists)
    {
        return null;
    }
    var files = info.GetFiles(deviceId + "_????.txt");
    int numberOfMessage = files.Length;
    var file = files.OrderBy(x => x.CreationTime).FirstOrDefault();
    if (file == null)
    {
        return new SendDefinition
                   {
                       Message = string.Empty,
                       NumberOfMessages = 0
                   };
    }
    string response;
    using (var reader = new StreamReader(file.FullName))
    {
        response = reader.ReadToEnd().Replace("'r'n", "");
    }
    string[] data = file.Name.Split('.');
    var name = data[0].Split('_');
    if (name.Length > 3)
    {
        var count = Convert.ToInt16(name[3],
                                    CultureInfo.InvariantCulture);
        if (count < 5)
        {
            count++;
            string newFileName = Path
                .Combine(storePath,
                         data[0].Substring(0, data[0].Length - 1)
                         + count + ".txt");
            file.CopyTo(newFileName, true);
        }
        file.Delete();
    }
    else
    {        
        string newFileName = Path.Combine(storePath,
                                          data[0] + "_0.txt");
        file.CopyTo(newFileName, true);
        file.Delete();
    }
    return new SendDefinition
                   {
                       Message = response,
                       NumberOfMessages = numberOfMessage
                   };
}

我想,好吧,设备ID位一定是垃圾,但查看日志输出,我得到了:

Definition for '3912'

我认为引发该异常的代码行如下,但我没有PDB,所以我不能100%确定,因此发布了整个函数。

var files = info.GetFiles(deviceId + "_????.txt");

我查看了Path.GetInvalidPathChars MSDN页面,查看了哪些无效字符,我认为将"3912_????.txt"传递到该函数中应该很好。

我想目录一定很好,否则整个.Exists就会崩溃。

那么,任何一个伟大的StackOverflow都知道是什么可能导致了这种情况吗(我刚刚重新启动了我的应用程序,还没有看到它再次发生…)?

更新

在该目录中执行目录时,我有以下内容:

14.03.2012  16:03    <DIR>          .
14.03.2012  16:03    <DIR>          ..
09.03.2012  13:51               101 3055_P_275112090312.txt
25.01.2012  10:52                99 3055_X_325209250112.txt
10.02.2012  08:38                74 3055_Z_373807100212.txt
           3 Datei(en)            274 Bytes
           2 Verzeichnis(se), 33.613.897.728 Bytes frei

是什么原因导致Directory.GetFiles出现此ArgumentException

最可能的原因是deviceId包含无效字符。

例如,后面的null字符("''0")会给出这个结果,并且可能不会显示在日志中。

您可以通过跟踪设备ID字符串中每个字符的值来检查这一点,例如:

Console.WriteLine("Device Id {0} ({1})", 
    deviceId,
    String.Join("-", deviceId.Select(x => ((int)x).ToString("X2")).ToArray()));

查看堆栈跟踪,它似乎在给定目录中的匹配文件中循环,然后尝试使用Path.InternalCombine()获取完整路径。这将检查是否存在无效字符,从而引发异常。

由于storePath变量中的无效字符本应在DirectoryInfo构造函数中引发异常,因此我只看到无效字符可能以一种方式潜入:

目录中的一个文件名包含非法字符

听起来很傻,但奇怪的事情发生了。。。您可以通过从该目录中获取文件列表来检查这是否是原因,最好是通过在命令行上运行dir命令,并将结果管道传输到文本文件中。

编辑:
我刚刚看到你已经这么做了——看来我错了。在这种情况下,我同意乔的观点,唯一剩下的嫌疑人是deviceId。看看您是否可以记录字符串的十六进制表示,如图所示,它还应该显示'0和任何其他特殊字符。

我在扫描mac上的目录(通过网络共享)时遇到了这个问题。

DirectoryInfo.GetFiles(@"//macbook/sharedfolder")

附带地说,在mac上使用<,>,?这样的字符是非常合法的,?在文件名中,但在windows中不是。

当目录中的一个文件名有无效字符时,我得到了这个"非法字符"错误。

我在尝试调用
时遇到此异常new DirectoryInfo(folderPath).GetFiles("x??''*.dll")

据我所知,GetFiles()不支持使用通配符作为目录名。因此,我使用了以下语句,该语句有效:
new DirectoryInfo(folderPath).GetDirectories("x??").SelectMany(d => d.GetFiles("*.dll"))

我正在尝试获取所有与基本文件名匹配的文件,然后在文件扩展名之前加下划线。当我这样做的时候,我也会遇到同样的错误。

    DirectoryInfo di = new DirectoryInfo(txtAlternateImagesFolder.Text);
    string matchPattern = imageFileName.Replace(".jpg", "_*.jpg");
    var alternates = di.GetFiles(@matchPattern);

然后我尝试了这个:

string matchPattern = imageFileName.Replace(".jpg", "");
var alternates = di.GetFiles(matchPattern).Where(f => f.Name.Contains(matchPattern) && f.Name!=imageFileName);

我没有收到错误,但也没有找到匹配的文件。我需要导致异常的通配符"*"。所以我的下一次尝试是:

    DirectoryInfo di = new DirectoryInfo($@"   {txtAlternateImagesFolder.Text}");
var images = di.GetFiles("*.jpg");
//Skipping some use feedback code
        string matchPattern = imageFileName.Replace(".jpg", "*.jpg");
        var matches = images.Where(f => f.Name.Contains(matchPattern) && f.Name != imageFileName);

我的理论是,如果我在GetFiles()方法中正常使用通配符,但在Where()谓词中不使用通配符,它可能不会爆炸。理论不错,但没有乐趣。最后,我不得不通过将带有通配符的匹配定义为"包含没有扩展名的文件名,但与文件名不同"来强化它。

你不能有一个?在文件名中。' / : * ? " < > |不是文件名的有效字符。

编辑:CheckInvalidPathChars正在查找以下字符:

num==34||num==60||num===62||num==124||num<32

为什么不在代码中实现这一点,并抛出/处理自己的异常呢。