38

.Netで、パスを表す文字列に無効な文字が含まれていないかどうかを確認する方法はありますか?Path.InvalidPathCharsの各文字を繰り返し処理して、文字列に文字が含まれているかどうかを確認できることはわかっていますが、単純な、おそらくより正式なソリューションをお勧めします。

ありますか?

Getに対してチェックするだけでは、まだ例外が発生することがわかりました

アップデート:

GetInvalidPathCharsがすべての無効なパス文字をカバーしているわけではないことがわかりました。GetInvalidFileNameCharsには、私が遭遇した「?」を含む5つがあります。私はそれに切り替えるつもりです、そしてそれも不十分であることが判明した場合は報告します。

アップデート2:

GetInvalidFileNameCharsは間違いなく私が望むものではありません。これには、絶対パスに含まれる':'( "C:\ whatever")が含まれます。結局、GetInvalidPathCharsを使用して、「?」を追加する必要があると思います。そして、それらが出てきたときに私に問題を引き起こす他のキャラクター。より良いソリューションを歓迎します。

4

9 に答える 9

48

InvalidPathCharsは非推奨になりました。代わりにGetInvalidPathChars()を使用してください。

    public static bool FilePathHasInvalidChars(string path)
    {

        return (!string.IsNullOrEmpty(path) && path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) >= 0);
    }

編集:少し長くなりますが、1つの関数でパスとファイルの無効な文字を処理します:

    // WARNING: Not tested
    public static bool FilePathHasInvalidChars(string path)
    {
        bool ret = false;
        if(!string.IsNullOrEmpty(path))
        {
            try
            {
                // Careful!
                //    Path.GetDirectoryName("C:\Directory\SubDirectory")
                //    returns "C:\Directory", which may not be what you want in
                //    this case. You may need to explicitly add a trailing \
                //    if path is a directory and not a file path. As written, 
                //    this function just assumes path is a file path.
                string fileName = System.IO.Path.GetFileName(path);
                string fileDirectory = System.IO.Path.GetDirectoryName(path);

                // we don't need to do anything else,
                                    // if we got here without throwing an 
                                    // exception, then the path does not
                                    // contain invalid characters
            }
            catch (ArgumentException)
            {
                                    // Path functions will throw this 
                                    // if path contains invalid chars
                ret = true;
            }
        }
        return ret;
    }
于 2010-03-12T21:13:35.260 に答える
9

に依存する場合は注意が必要Path.GetInvalidFileNameCharsです。これは、思ったほど信頼できない場合があります。次のMSDNドキュメントの次の注釈に注意してくださいPath.GetInvalidFileNameChars

このメソッドから返される配列には、ファイル名とディレクトリ名で無効な文字の完全なセットが含まれているとは限りません。無効な文字の完全なセットは、ファイルシステムによって異なる場合があります。たとえば、Windowsベースのデスクトッププラットフォームでは、無効なパス文字には、ASCII / Unicode文字1〜31、引用符( ")、より小さい(<)、より大きい(>)、パイプ(|)、バックスペース( \ b)、null(\ 0)およびタブ(\ t)。

それは方法でこれ以上良くはありませんPath.GetInvalidPathChars。まったく同じコメントが含まれています。

于 2011-11-16T13:34:24.107 に答える
5

.NET 4.7.2以降Path.GetInvalidFileNameChars()、次の41個の「不良」文字を報告します。

0x0000 0'\ 0'| 0x000d 13'\ r'| 0x001b 27'\ u001b'
0x0001 1'\ u0001' | 0x000e 14'\ u000e' | 0x001c 28'\ u001c'
0x0002 2'\ u0002' | 0x000f 15'\ u000f' | 0x001d 29'\ u001d'
0x0003 3'\ u0003' | 0x0010 16'\ u0010' | 0x001e 30'\ u001e'
0x0004 4'\ u0004' | 0x0011 17'\ u0011' | 0x001f 31'\ u001f'
0x0005 5'\ u0005' | 0x0012 18'\ u0012' | 0x0022 34'"'
0x0006 6'\ u0006' | 0x0013 19'\ u0013' | 0x002a 42'*'
0x0007 7'\ a'| 0x0014 20'\ u0014' | 0x002f 47'/'
0x0008 8'\ b'| 0x0015 21'\ u0015' | 0x003a 58':'
0x0009 9'\ t'| 0x0016 22'\ u0016' | 0x003c 60'<'
0x000a 10'\ n'| 0x0017 23'\ u0017' | 0x003e 62'>'
0x000b 11'\ v'| 0x0018 24'\ u0018' | 0x003f 63'?'
0x000c 12'\ f'| 0x0019 25'\ u0019' | 0x005c 92'\\'
                        | 0x001a 26'\ u001a' | 0x007c 124'|'

別のポスターで指摘されているように、これは。によって返される文字のセットの適切なスーパーセットPath.GetInvalidPathChars()です。

次の関数は、上記の41文字の正確なセットを検出します。

public static bool IsInvalidFileNameChar(Char c) => c < 64U ?
        (1UL << c & 0xD4008404FFFFFFFFUL) != 0 :
        c == '\\' || c == '|';
于 2018-09-04T00:39:47.593 に答える
4

結局、いくつかの内部.NET実装を借用して組み合わせて、パフォーマンスの高いメソッドを考え出しました。

/// <summary>Determines if the path contains invalid characters.</summary>
/// <remarks>This method is intended to prevent ArgumentException's from being thrown when creating a new FileInfo on a file path with invalid characters.</remarks>
/// <param name="filePath">File path.</param>
/// <returns>True if file path contains invalid characters.</returns>
private static bool ContainsInvalidPathCharacters(string filePath)
{
    for (var i = 0; i < filePath.Length; i++)
    {
        int c = filePath[i];

        if (c == '\"' || c == '<' || c == '>' || c == '|' || c == '*' || c == '?' || c < 32)
            return true;
    }

    return false;
}

それから私はそれをそのように使用しましたが、安全のためにtry /catchブロックで包みました:

if ( !string.IsNullOrWhiteSpace(path) && !ContainsInvalidPathCharacters(path))
{
    FileInfo fileInfo = null;

    try
    {
        fileInfo = new FileInfo(path);
    }
    catch (ArgumentException)
    {            
    }

    ...
}
于 2015-12-08T05:55:40.713 に答える
2

おそらくあなたには手遅れですが、他の誰かを助けるかもしれません。私は同じ問題に直面し、パスをサニタイズするための信頼できる方法を見つける必要がありました。

これが私が3つのステップで使用することになったものです:

ステップ1:カスタムクリーニング。

public static string RemoveSpecialCharactersUsingCustomMethod(this string expression, bool removeSpecialLettersHavingASign = true)
{
    var newCharacterWithSpace = " ";
    var newCharacter = "";

    // Return carriage handling
    // ASCII LINE-FEED character (LF),
    expression = expression.Replace("\n", newCharacterWithSpace);
    // ASCII CARRIAGE-RETURN character (CR) 
    expression = expression.Replace("\r", newCharacterWithSpace);

    // less than : used to redirect input, allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"<", newCharacter);
    // greater than : used to redirect output, allowed in Unix filenames, see Note 1
    expression = expression.Replace(@">", newCharacter);
    // colon: used to determine the mount point / drive on Windows; 
    // used to determine the virtual device or physical device such as a drive on AmigaOS, RT-11 and VMS; 
    // used as a pathname separator in classic Mac OS. Doubled after a name on VMS, 
    // indicates the DECnet nodename (equivalent to a NetBIOS (Windows networking) hostname preceded by "\\".). 
    // Colon is also used in Windows to separate an alternative data stream from the main file.
    expression = expression.Replace(@":", newCharacter);
    // quote : used to mark beginning and end of filenames containing spaces in Windows, see Note 1
    expression = expression.Replace(@"""", newCharacter);
    // slash : used as a path name component separator in Unix-like, Windows, and Amiga systems. 
    // (The MS-DOS command.com shell would consume it as a switch character, but Windows itself always accepts it as a separator.[16][vague])
    expression = expression.Replace(@"/", newCharacter);
    // backslash : Also used as a path name component separator in MS-DOS, OS/2 and Windows (where there are few differences between slash and backslash); allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"\", newCharacter);
    // vertical bar or pipe : designates software pipelining in Unix and Windows; allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"|", newCharacter);
    // question mark : used as a wildcard in Unix, Windows and AmigaOS; marks a single character. Allowed in Unix filenames, see Note 1
    expression = expression.Replace(@"?", newCharacter);
    expression = expression.Replace(@"!", newCharacter);
    // asterisk or star : used as a wildcard in Unix, MS-DOS, RT-11, VMS and Windows. Marks any sequence of characters 
    // (Unix, Windows, later versions of MS-DOS) or any sequence of characters in either the basename or extension 
    // (thus "*.*" in early versions of MS-DOS means "all files". Allowed in Unix filenames, see note 1
    expression = expression.Replace(@"*", newCharacter);
    // percent : used as a wildcard in RT-11; marks a single character.
    expression = expression.Replace(@"%", newCharacter);
    // period or dot : allowed but the last occurrence will be interpreted to be the extension separator in VMS, MS-DOS and Windows. 
    // In other OSes, usually considered as part of the filename, and more than one period (full stop) may be allowed. 
    // In Unix, a leading period means the file or folder is normally hidden.
    expression = expression.Replace(@".", newCharacter);
    // space : allowed (apart MS-DOS) but the space is also used as a parameter separator in command line applications. 
    // This can be solved by quoting, but typing quotes around the name every time is inconvenient.
    //expression = expression.Replace(@"%", " ");
    expression = expression.Replace(@"  ", newCharacter);

    if (removeSpecialLettersHavingASign)
    {
        // Because then issues to zip
        // More at : http://www.thesauruslex.com/typo/eng/enghtml.htm
        expression = expression.Replace(@"ê", "e");
        expression = expression.Replace(@"ë", "e");
        expression = expression.Replace(@"ï", "i");
        expression = expression.Replace(@"œ", "oe");
    }

    return expression;
}

手順2:まだ削除されていない無効な文字を確認します。

追加の検証手順として、Path.GetInvalidPathChars()上記の方法を使用して、まだ削除されていない潜在的な無効な文字を検出します。

public static bool ContainsAnyInvalidCharacters(this string path)
{
    return (!string.IsNullOrEmpty(path) && path.IndexOfAny(Path.GetInvalidPathChars()) >= 0);
}

手順3:手順2で検出された特殊文字をすべて削除します。

そして最後に、私はこの方法を最後のステップとして使用して、残っているものをすべてきれいにします。(パスとファイル名から不正な文字を削除する方法から?):

public static string RemoveSpecialCharactersUsingFrameworkMethod(this string path)
{
    return Path.GetInvalidFileNameChars().Aggregate(path, (current, c) => current.Replace(c.ToString(), string.Empty));
}

最初のステップでクリーンアップされなかった無効な文字をログに記録します。「リーク」が検出されるとすぐに、カスタムメソッドを改善するためにその方法を選択します。Path.GetInvalidFileNameChars()上記で報告された次のステートメント(MSDNから)のため、私は信頼できません:

「このメソッドから返される配列には、ファイル名とディレクトリ名で無効な文字の完全なセットが含まれているとは限りません。」

これは理想的なソリューションではないかもしれませんが、私のアプリケーションのコンテキストと必要な信頼性のレベルを考えると、これは私が見つけた最良のソリューションです。

于 2015-11-09T12:18:04.880 に答える
1

HashSet効率を上げるために、これにを使用することをお勧めします。

private static HashSet<char> _invalidCharacters = new HashSet<char>(Path.GetInvalidPathChars());

次に、文字列がnull /空ではなく、無効な文字がないことを簡単に確認できます。

public static bool IsPathValid(string filePath)
{
    return !string.IsNullOrEmpty(filePath) && !filePath.Any(pc => _invalidCharacters.Contains(pc));
}

オンラインでお試しください

于 2019-11-26T04:34:58.310 に答える
0

私も手遅れです。ただし、ユーザーがパスとして有効なものを入力したかどうかを検証することがタスクである場合は、パスを組み合わせたソリューションがあります。

Path.GetInvalidFileNameChars()C:ファイルに対して不正な文字のリストを返しますが、ディレクトリは、セパレータ(システムから取得できます)とルート指定子(検索から削除できます)を除いて、ファイルのルールに従います。はい、Path.GetInvalidFileNameChars()完全なセットではありませんが、すべてを手動で検索するよりも優れています。

それで:

private static bool CheckInvalidPath(string targetDir)
{
  string root;
  try
  {
    root = Path.GetPathRoot(targetDir);
  }
  catch
  {
    // the path is definitely invalid if it has crashed
    return false;
  }

  // of course it is better to cache it as it creates
  // new array on each call
  char[] chars = Path.GetInvalidFileNameChars();

  // ignore root
  for (int i = root.Length; i < targetDir.Length; i++)
  {
    char c = targetDir[i];

    // separators are allowed
    if (c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar)
      continue;

    // check for illegal chars
    for (int j = 0; j < chars.Length; j++)
      if (c == chars[j])
        return false;
  }

  return true;
}

のようなメソッドは(完全に無効な)Path.GetFileNameのようなパスではクラッシュせずC:\*、例外ベースのチェックでさえ十分ではないことがわかりました。クラッシュする唯一のものPath.GetPathRootは無効なルートです(のようにCC:\someDir)。したがって、他のすべては手動で行う必要があります。

于 2018-07-04T15:01:11.463 に答える
0

MSのドキュメントを検討できる限り、シンプルで正確です。

bool IsPathValid(String path)
{
    for (int i = 0; i < path.Length; ++i)
        if (Path.GetInvalidFileNameChars().Contains(path[i]))
            return false
    return true;
}
于 2020-07-08T00:35:41.247 に答える
0

参考までに、フレームワークにはこれを行う内部メソッドがありますが、残念ながらそれらはマークされていinternalます。

ここで参照するために、ここで受け入れられた答えに類似している関連するビットがあります。

internal static bool HasIllegalCharacters(string path, bool checkAdditional = false) => (AppContextSwitches.UseLegacyPathHandling || !PathInternal.IsDevice(path)) && PathInternal.AnyPathHasIllegalCharacters(path, checkAdditional);

    internal static bool AnyPathHasIllegalCharacters(string path, bool checkAdditional = false)
    {
      if (path.IndexOfAny(PathInternal.InvalidPathChars) >= 0)
        return true;
      return checkAdditional && PathInternal.AnyPathHasWildCardCharacters(path);
    }

    internal static bool HasWildCardCharacters(string path)
    {
      int startIndex = AppContextSwitches.UseLegacyPathHandling ? 0 : (PathInternal.IsDevice(path) ? "\\\\?\\".Length : 0);
      return PathInternal.AnyPathHasWildCardCharacters(path, startIndex);
    }

    internal static bool AnyPathHasWildCardCharacters(string path, int startIndex = 0)
    {
      for (int index = startIndex; index < path.Length; ++index)
      {
        switch (path[index])
        {
          case '*':
          case '?':    
            return true;
          default:
            continue;
        }
      }
      return false;
    }
于 2020-11-04T22:23:18.880 に答える