Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What could cause this ArgumentException from Directory.GetFiles?

Tags:

c#

.net

The following snippet of code has been working fine for weeks but today I got this exception:

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)
    ...

Here is the code

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
                   };

}

I thought, OK, the deviceId bit must be junk but looking in the log output I got:

Definition for '3912'

I think that the line of code that would be throwing that exception is the following but I do not have PDBs so I am not 100% sure hence posting the entire function.

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

I checked the Path.GetInvalidPathChars MSDN page to see what invalid characters are and I think that passing "3912_????.txt" into that function should be fine.

I figure the directory must be fine or that whole .Exists thing would have fallen over.

So do any of the great StackOverfloweions know what could possibly have made this happen (I just restarted my application and have not seen it happen again yet...)?

Update

Doing a dir in that directory I have the following:

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
like image 704
kmp Avatar asked Mar 14 '12 15:03

kmp


2 Answers

The most likely reason is that deviceId contains an invalid character.

For example, a trailing null character ("\0") would give this result, and would probably not show up in your log.

You could check for this by tracing the values of each character in your deviceId string - e.g.:

Console.WriteLine("Device Id {0} ({1})", 
    deviceId,
    String.Join("-", deviceId.Select(x => ((int)x).ToString("X2")).ToArray()));
like image 192
Joe Avatar answered Oct 15 '22 10:10

Joe


Looking at the stack trace, it seems to be cycling through the matching files in the given directory, and then trying to obtain a full path using Path.InternalCombine(). That checks the for invalid characters, which throws the exception.

Since invalid characters in your storePath variable should have thrown an exception in the DirectoryInfo constructor, I see only one ways that an invalid character could creep in:

One of the file names in the directory contains an illegal character.

Sounds silly, but stranger things have happened... You can check if that is the cause by getting a file listing from that directory, preferably by running the dir command on the command line, and piping the result into a text file.

Edit:
Just saw that you already did - and it seems I was wrong. In that case I concur with Joe, the only remaining suspect is the deviceId. See if you can log a hex representation of the string, as shown here, that should also show \0 and any other special characters.

like image 23
Treb Avatar answered Oct 15 '22 08:10

Treb