23

I've wrote this little method to achieve the goal in the subj., however, is there more efficient (simpler) way of doing this? I hope this can help somebody who will search for this like I did.

var fileName = new System.Text.StringBuilder();
fileName.Append("*Bad/\ :, Filename,? ");
// get rid of invalid chars
while (fileName.ToString().IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) > -1)
{
    fileName = fileName.Remove(fileName.ToString().IndexOfAny(System.IO.Path.GetInvalidFileNameChars()), 1);
}

?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Ruslan
  • 9,927
  • 15
  • 55
  • 89

4 Answers4

120

I know this is a few years old but here is another solution for reference.

public string GetSafeFilename(string filename)
{

    return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));

}
Ceres
  • 3,524
  • 3
  • 18
  • 25
  • 1
    A few years later, but a very clever solution, anyway. As of 2014, still the one I'm gonna use, instead of a Regex.Replace. =D – Anderson Pimentel Feb 18 '14 at 15:46
  • Yep. Best solution. It also shows that it pays to read the entire thread (and to answer old questions). Thanks, Ceres. –  Jun 21 '16 at 01:19
  • 2
    @Rob `GetInvalidFileNameChars()` does include '\' and '/'. This routine assumes you are passing a filename only. If you were checking part of the file path you could use `Path.GetInvalidPathChars()` instead. – Ceres May 16 '18 at 15:04
  • Applies too for folder name? – Kiquenet Oct 04 '22 at 13:42
  • @Kiquenet `GetInvalidPathChars()` for folders and `GetInvalidFileNameChars()` for filenames – Ceres Oct 05 '22 at 11:41
  • `Path.InvalidPathChars` does not include the **wildcard characters** *, ?, and also :, \, /, <, and > and also " – Kiquenet Oct 05 '22 at 13:52
17

Try the following

public string MakeValidFileName(string name) {
  var builder = new StringBuilder();
  var invalid = System.IO.Path.GetInvalidFileNameChars();
  foreach ( var cur in name ) {
    if ( !invalid.Contains(cur) ) {
      builder.Append(cur);
    }
  }
  return builder.ToString();
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
14

A different approach that is compatible with .NET 4. See my comments above explaining the need.

public static string ScrubFileName(string value)
{
   var sb = new StringBuilder(value);
   foreach (char item in Path.GetInvalidFileNameChars())
   {
      sb.Replace(item.ToString(), "");
   }
   return sb.ToString();
}
Roland Schaer
  • 1,656
  • 1
  • 22
  • 30
-1

If you look for "concise" when you say simple:

public string StripInvalidChars(string filename) {
  return new String(
    filename.Except(System.IO.Path.GetInvalidFileNameChars()).ToArray()
  );
}

That said, I'd go with JaredPar's solution. It's probably easier to read (depending on taste, background), my gut feeling is that it is more efficient (although I'm not sure how efficient you have to be stripping that dozen of invalid chars from a limited length filename) and his use of a StringBuilder() seems to fit perfectly to your example.

Benjamin Podszun
  • 9,679
  • 3
  • 34
  • 45
  • 3
    I don't believe the Except method does what you were wanting here. It doesn't really work with duplicates. "[The Except] method returns those elements in first that do not appear in second. It does not also return those elements in second that do not appear in first." via http://msdn.microsoft.com/en-us/library/bb300779.aspx – ChronoPositron Apr 22 '10 at 22:54
  • @ChronoPositron: Enlighten me: What is the the problem? I want "those elements in first that do not appear in second" (i.e. the chars that are not invalid). I don't want "those elements in second that do not appear in first" (i.e. the invalid chars that are not present). – Benjamin Podszun Apr 23 '10 at 22:24
  • @Bejamin Podszun: The issue is that Except works as a set operation. For example, if I pass in "aaabbb.txt" (which is a valid filename) to your function, the resulting value is "ab.tx". It is only keeping the first occurrence of each letter, which makes it remove a lot more than just the invalid characters; it changes the expected outcome of the function. – ChronoPositron Apr 26 '10 at 15:44
  • 1
    @ChronoPositron: Whoa, you got me now. I was missing the "set" part before and when I quickly tested this in LINQPad with the testdata of the OP I merely noticed the removed invalid chars (good) and not the missing valid elements (bad). Sorry for being slow and thanks for enlightening me. – Benjamin Podszun Apr 26 '10 at 16:14
  • could you please edit your post and add a warning? – Bernhard Jan 15 '20 at 09:07