102

What is the best way to combine a path with a filename?

That is, given c:\foo and bar.txt, I want c:\foo\bar.txt.

Given c:\foo and ..\bar.txt, I want either an error or c:\foo\bar.txt (so I cannot use Path.Combine() directly). Similarly for c:\foo and bar/baz.txt, I want an error or c:\foo\baz.txt (not c:\foo\bar\baz.txt).

I realize, I could check that the filename does not contain '\' or '/', but is that enough? If not, what is the correct check?

Luiso
  • 4,173
  • 2
  • 37
  • 60
Rasmus Faber
  • 48,631
  • 24
  • 141
  • 189

3 Answers3

144

If you want "bad" filenames to generate an error:

if (Path.GetFileName(fileName) != fileName)
{
    throw new Exception("'fileName' is invalid!");
}
string combined = Path.Combine(dir, fileName);

Or, if you just want to silently correct "bad" filenames without throwing an exception:

string combined = Path.Combine(dir, Path.GetFileName(fileName));
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 21
    For those less familiar with the framework, you need a `using System.IO;` call in your file to get access to `Path`. – Robert Gowland Sep 07 '12 at 13:41
  • 3
    Note that `Path.Combine` will throw an `ArgumentNullException` if either of its arguments are `null`. You **can** pass an empty string to either argument – Aaron Blenkush Mar 01 '13 at 23:23
  • 4
    Note: Path.Combine will normally add a separator between each path if needed. However, Path.Combine("C:", "file.txt"), returns "C:file.txt", which is not a valid path. – ConditionRacer Jul 25 '14 at 21:12
  • 1
    Note that this will still allow `fileName` to be `..` and result in something like `C:\path\to\..`. Tested here: https://dotnetfiddle.net/DoeH8K. Depending on use case, you may also want to validate that `fileName` is a valid filename (and not a "special filename" like `..` and maybe `nul`, `con`, ...). – Florian Winter Jan 17 '22 at 08:36
23

You could use:

Path.Combine(folder, Path.GetFileName(fileName))

or, to skip out the \ (not tested, maybe the Path.GetFileName handles this automatically)

Path.Combine(folder, Path.GetFileName(fileName.Replace("/","\\")))
GvS
  • 52,015
  • 16
  • 101
  • 139
3

Be aware that when you use Path.Combine(arg1, arg2) - if your user inputs a fully-qualified file path for arg2 it will disregard arg1, and use arg2 as the path.

In my opinion, Microsoft screwed up there! This can leave you wide open with the user hacking your entire filesystem. Be warned, read the fine print! If you're combining paths use: var newPath = path1 + @"\" + path2; simpler and no unexpected results...

Donnelle
  • 5,689
  • 3
  • 27
  • 31
Ravi
  • 41
  • 1
  • 1
    A full path on the right side being returned as the result of combining relative paths is a correct and valid result. – Matthew Whited Jun 21 '15 at 15:50
  • 2
    Regardless on if its a correct and valid result, too many devs are missing the fact that if in their code arg1 is a folder path and arg2 is user input, an absolute path inputed arg2 will be the resulting output. Makes it too easy to open up to in my opinion the worst of web app hacks..code/shell injection...Check your input guys. – Cyassin Aug 08 '16 at 00:09
  • 2
    In my opinion, any developer that thinks it is okay to allow a user to type paths in with no checking whatsoever -- deserves to be hacked. This is Day One stuff and Path.Combine is not designed to work the way you think it should -- it is a decent and robust way to avoid having to check for the terminal backslash, which is actually intended for internal use by your code, not as a front end to secure your files. The documentation for it is quite complete -- just read it. – jinzai Dec 19 '17 at 20:13