it-swarm-ko.tech

주어진 문자열이 Windows에서 유효한 / 유효한 파일 이름인지 어떻게 확인합니까?

응용 프로그램에 배치 파일 이름 바꾸기 기능을 포함하고 싶습니다. 사용자는 대상 파일 이름 패턴을 입력 할 수 있으며 (패턴에서 일부 와일드 카드를 바꾼 후) Windows에서 올바른 파일 이름인지 확인해야합니다. [a-zA-Z0-9_]+와 같은 정규식을 사용하려고했지만 다양한 언어 (예 : 움라우트 등)의 국가 별 문자가 많이 포함되어 있지 않습니다. 그러한 점검을 수행하는 가장 좋은 방법은 무엇입니까?

155
tomash

Path.GetInvalidPathCharsGetInvalidFileNameChars 에서 유효하지 않은 문자 목록을 얻을 수 있습니다.

UPD : 정규식에서이를 사용하는 방법에 대해서는 Steve Cooper의 제안 을 참조하십시오.

UPD2 : MSDN의 비고 섹션에 따르면 "이 메서드에서 반환 된 배열에 유효하지 않은 전체 문자 집합이 포함되어 있지는 않습니다. 파일 및 디렉토리 이름. " sixlettervaliables에서 제공하는 답변 자세한 내용을 설명합니다.

97
Eugene Katz

MSDN의 "파일 또는 디렉토리 이름 지정" 에서 Windows의 유효한 파일 이름에 대한 일반적인 규칙은 다음과 같습니다.

다음을 제외하고 현재 코드 페이지 (유니 코드/ANSI 127 이상)에 문자를 사용할 수 있습니다.

  • <>:"/\|?*
  • 정수 표현이 0-31 인 문자 (ASCII 공백 미만)
  • 대상 파일 시스템이 허용하지 않는 다른 문자 (예 : 후행 또는 공백)
  • DOS 이름 : CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 (및 AUX.txt 등을 피하십시오)
  • 파일 이름은 모두 마침표입니다

몇 가지 선택 사항을 확인하십시오.

  • 파일 경로를 포함한 파일 경로는 260자를 초과 할 수 없습니다 (\?\ 접두사를 사용하지 않음)
  • \?\를 사용할 때 32,000자를 초과하는 유니 코드 파일 경로 (파일 이름 포함)
119
user7116

. Net Frameworks 3.5 의 경우 다음과 같이 작동합니다.

정규식 일치는 당신에게 어떤 길을 가져다 줄 것입니다. 다음은 System.IO.Path.InvalidPathChars 상수를 사용하는 스 니펫입니다.

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("[" 
          + Regex.Escape(System.IO.Path.InvalidPathChars) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

. Net Frameworks 3.0 의 경우 다음과 같이 작동합니다.

http://msdn.Microsoft.com/en-us/library/system.io.path.getinvalidpathchars (v = vs.90) .aspx

정규식 일치는 당신에게 어떤 길을 가져다 줄 것입니다. 다음은 System.IO.Path.GetInvalidPathChars() 상수를 사용하는 스 니펫입니다.

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("["
          + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

알고 있으면 다른 형식도 확인해야합니다 (예 : c:\my\drive\\server\share\dir\file.ext

63
Steve Cooper

그것을 사용하고 오류를 잡으십시오. 허용되는 집합은 파일 시스템이나 다른 버전의 Windows에서 변경 될 수 있습니다. 다시 말해, Windows가 이름을 좋아하는지 알고 싶다면 이름을 알려주고 알려주십시오.

25

이 클래스는 파일 이름과 경로를 정리합니다. 처럼 사용

var myCleanPath = PathSanitizer.SanitizeFilename(myBadPath, ' ');

코드는 다음과 같습니다.

/// <summary>
/// Cleans paths of invalid characters.
/// </summary>
public static class PathSanitizer
{
    /// <summary>
    /// The set of invalid filename characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidFilenameChars;
    /// <summary>
    /// The set of invalid path characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidPathChars;

    static PathSanitizer()
    {
        // set up the two arrays -- sorted once for speed.
        invalidFilenameChars = System.IO.Path.GetInvalidFileNameChars();
        invalidPathChars = System.IO.Path.GetInvalidPathChars();
        Array.Sort(invalidFilenameChars);
        Array.Sort(invalidPathChars);

    }

    /// <summary>
    /// Cleans a filename of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizeFilename(string input, char errorChar)
    {
        return Sanitize(input, invalidFilenameChars, errorChar);
    }

    /// <summary>
    /// Cleans a path of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizePath(string input, char errorChar)
    {
        return Sanitize(input, invalidPathChars, errorChar);
    }

    /// <summary>
    /// Cleans a string of invalid characters.
    /// </summary>
    /// <param name="input"></param>
    /// <param name="invalidChars"></param>
    /// <param name="errorChar"></param>
    /// <returns></returns>
    private static string Sanitize(string input, char[] invalidChars, char errorChar)
    {
        // null always sanitizes to null
        if (input == null) { return null; }
        StringBuilder result = new StringBuilder();
        foreach (var characterToTest in input)
        {
            // we binary search for the character in the invalid set. This should be lightning fast.
            if (Array.BinarySearch(invalidChars, characterToTest) >= 0)
            {
                // we found the character in the array of 
                result.Append(errorChar);
            }
            else
            {
                // the character was not found in invalid, so it is valid.
                result.Append(characterToTest);
            }
        }

        // we're done.
        return result.ToString();
    }

}
23
Steve Cooper

이것이 내가 사용하는 것입니다 :

    public static bool IsValidFileName(this string expression, bool platformIndependent)
    {
        string sPattern = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$";
        if (platformIndependent)
        {
           sPattern = @"^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$";
        }
        return (Regex.IsMatch(expression, sPattern, RegexOptions.CultureInvariant));
    }

첫 번째 패턴은 Windows 플랫폼에 대해서만 유효하지 않은 불법 파일 이름 및 문자를 포함하는 정규식을 작성합니다. 두 번째는 동일하지만 이름이 모든 플랫폼에 합법적임을 보장합니다.

22
Scott Dorman

한 가지 코너 케이스를 염두에두면 처음 알게되었을 때 놀라게되었습니다. Windows는 파일 이름에 공백 문자를 허용합니다! 예를 들어 다음은 Windows에서 합법적이고 고유 한 파일 이름 (따옴표 제외)입니다.

"file.txt"
" file.txt"
"  file.txt"

이것에서 한 가지 탈취 : 파일 이름 문자열에서 선행/후행 공백을 자르는 코드를 작성할 때주의하십시오.

18
Jon Schneider

유진 카츠의 답변을 단순화 :

bool IsFileNameCorrect(string fileName){
    return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}

또는

bool IsFileNameCorrect(string fileName){
    return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
9
tmt

Microsoft Windows : Windows 커널은 1-31 범위의 문자 (예 : 0x01-0x1F)와 문자 "* : <>?\|를 사용할 수 없습니다. NTFS는 각 경로 구성 요소 (디렉토리 또는 파일 이름)의 길이가 255 자이며 최대 약 32767 자 길이의 Windows 커널은 최대 259 자 길이의 경로 만 지원하며, Windows는 MS-DOS 장치 이름 AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL 및 PRN뿐만 아니라 확장명 (예 : AUX.txt)이있는 이름 (사용시 제외) 긴 UNC 경로 (예 : \.\C :\nul.txt 또는 \?\D :\aux\con) (확장자가 제공되는 경우 CLOCK $이 사용될 수 있습니다.) 이러한 제한은 Windows에만 적용됩니다. 예를 들어 리눅스는 "* : <>?\| NTFS에서도.

출처 : http://en.wikipedia.org/wiki/Filename

8
Martin Faartoft

가능한 모든 문자를 명시 적으로 포함하는 대신 정규식을 사용하여 잘못된 문자가 있는지 확인한 다음 오류를보고 할 수 있습니다. 이상적으로 응용 프로그램은 사용자가 원하는대로 정확하게 파일 이름을 지정해야하며 오류가 발생하면 파울 링 만합니다.

7
ConroyP

나는 예외를 던지지 않고 파일 이름에서 유효하지 않은 문자를 제거하기 위해 이것을 사용합니다.

private static readonly Regex InvalidFileRegex = new Regex(
    string.Format("[{0}]", Regex.Escape(@"<>:""/\|?*")));

public static string SanitizeFileName(string fileName)
{
    return InvalidFileRegex.Replace(fileName, string.Empty);
}
6
JoelFan

또한 CON, PRN, AUX, NUL, COM # 및 기타 일부는 확장명을 가진 디렉토리의 합법적 인 파일 이름이 아닙니다.

5
Roland Rabien

문제는 경로 이름이 올바른 Windows 경로인지 또는 코드가 실행중인 시스템에서 유효한 인지 확인하려고합니까? ? 후자는 더 중요하다고 생각하므로 개인적으로 전체 경로를 분해하고 _mkdir을 사용하여 파일이 속한 디렉토리를 만든 다음 파일을 만들려고합니다.

이렇게하면 경로에 유효한 윈도우 문자 만 포함되어있을뿐만 아니라 실제로이 프로세스에서 쓸 수있는 경로를 나타내는 지 알 수 있습니다.

5
kfh

다른 답변을 보완하기 위해 고려해야 할 몇 가지 추가 Edge 사례가 있습니다.

4
Joe

MSDN 부터는 허용되지 않는 문자 목록이 있습니다.

다음을 제외하고 확장 코드 세트 (128–255)의 유니 코드 문자 및 문자를 포함하여 이름에 현재 코드 페이지의 거의 모든 문자를 사용하십시오.

  • 다음 예약 문자는 허용되지 않습니다 : <> : "/\|? *
  • 정수 표현이 0에서 31 사이의 문자는 허용되지 않습니다.
  • 대상 파일 시스템이 허용하지 않는 다른 문자.
3
Mark Biek

이 상황에서는 정규 표현식이 과도합니다. String.IndexOfAny()Path.GetInvalidPathChars()과 함께 Path.GetInvalidFileNameChars() 방법을 사용할 수 있습니다.

또한 Path.GetInvalidXXX() 메서드는 모두 내부 배열을 복제하고 복제본을 반환합니다. 따라서이 작업을 많이 (수천 번) 수행하려는 경우 재사용을 위해 유효하지 않은 문자 배열의 사본을 캐시 할 수 있습니다.

2
s n

또한 대상 파일 시스템이 중요합니다.

NTFS에서는 특정 파일에서 일부 파일을 만들 수 없습니다. 예 : 루트에서 $ Boot

2
Dominik Weber

이것은 이미 답변 된 질문이지만 "기타 옵션"을 위해서만 여기에 비 이상적인 질문이 있습니다.

(흐름 제어로 예외를 사용하는 것이 일반적으로 "나쁜 것"이기 때문에 비 이상적임)

public static bool IsLegalFilename(string name)
{
    try 
    {
        var fileInfo = new FileInfo(name);
        return true;
    }
    catch
    {
        return false;
    }
}
2
JerKimball

파일 이름/경로를 포함하는 문자열에 유효하지 않은 문자가 있는지 확인하려는 경우 가장 빠른 방법은 Split()을 사용하여 파일 이름을 어디에서나 부분 배열로 나누는 것입니다 유효하지 않은 문자. 결과가 1의 배열 인 경우 유효하지 않은 문자가 없습니다. :-)

var nameToTest = "Best file name \"ever\".txt";
bool isInvalidName = nameToTest.Split(System.IO.Path.GetInvalidFileNameChars()).Length > 1;

var pathToTest = "C:\\My Folder <secrets>\\";
bool isInvalidPath = pathToTest.Split(System.IO.Path.GetInvalidPathChars()).Length > 1;

LinqPad에서 파일 및 경로 이름 1,000,000 번에서 위에서 언급 한 다른 방법을 시도했습니다.

Split() 사용은 ~ 850ms에 불과합니다.

Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]") 사용은 약 6 초입니다.

Path 클래스에서 다양한 메소드를 사용하여 파일 이름을 얻고 내부 유효성 검사가 작업을 수행하도록하는 것과 같이 다른 옵션 중 일부와 마찬가지로 더 복잡한 정규 표현식은 상당히 나빠집니다. 예외 처리).

백만 개의 파일 이름을 유효성 검사해야하는 경우가 많지 않으므로 대부분의 이러한 방법에는 단일 반복이 적합합니다. 그러나 유효하지 않은 문자 만 찾는 경우에도 여전히 효율적이고 효과적입니다.

1
Nick Albrecht

파일 이름이 너무 길고 Windows 10 이전 환경에서 실행되는 경우 이러한 답변 중 대부분이 작동하지 않습니다. 마찬가지로 선행 또는 후행 허용은 기술적으로 유효하지만 파일을 각각 보거나 삭제하기 어려운 경우 문제가 발생할 수 있습니다.

유효한 파일 이름을 확인하기 위해 만든 유효성 검사 속성입니다.

public class ValidFileNameAttribute : ValidationAttribute
{
    public ValidFileNameAttribute()
    {
        RequireExtension = true;
        ErrorMessage = "{0} is an Invalid Filename";
        MaxLength = 255; //superseeded in modern windows environments
    }
    public override bool IsValid(object value)
    {
        //http://stackoverflow.com/questions/422090/in-c-sharp-check-that-filename-is-possibly-valid-not-that-it-exists
        var fileName = (string)value;
        if (string.IsNullOrEmpty(fileName)) { return true;  }
        if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 ||
            (!AllowHidden && fileName[0] == '.') ||
            fileName[fileName.Length - 1]== '.' ||
            fileName.Length > MaxLength)
        {
            return false;
        }
        string extension = Path.GetExtension(fileName);
        return (!RequireExtension || extension != string.Empty)
            && (ExtensionList==null || ExtensionList.Contains(extension));
    }
    private const string _sepChar = ",";
    private IEnumerable<string> ExtensionList { get; set; }
    public bool AllowHidden { get; set; }
    public bool RequireExtension { get; set; }
    public int MaxLength { get; set; }
    public string AllowedExtensions {
        get { return string.Join(_sepChar, ExtensionList); } 
        set {
            if (string.IsNullOrEmpty(value))
            { ExtensionList = null; }
            else {
                ExtensionList = value.Split(new char[] { _sepChar[0] })
                    .Select(s => s[0] == '.' ? s : ('.' + s))
                    .ToList();
            }
    } }

    public override bool RequiresValidationContext => false;
}

그리고 시험

[TestMethod]
public void TestFilenameAttribute()
{
    var rxa = new ValidFileNameAttribute();
    Assert.IsFalse(rxa.IsValid("pptx."));
    Assert.IsFalse(rxa.IsValid("pp.tx."));
    Assert.IsFalse(rxa.IsValid("."));
    Assert.IsFalse(rxa.IsValid(".pp.tx"));
    Assert.IsFalse(rxa.IsValid(".pptx"));
    Assert.IsFalse(rxa.IsValid("pptx"));
    Assert.IsFalse(rxa.IsValid("a/abc.pptx"));
    Assert.IsFalse(rxa.IsValid("a\\abc.pptx"));
    Assert.IsFalse(rxa.IsValid("c:abc.pptx"));
    Assert.IsFalse(rxa.IsValid("c<abc.pptx"));
    Assert.IsTrue(rxa.IsValid("abc.pptx"));
    rxa = new ValidFileNameAttribute { AllowedExtensions = ".pptx" };
    Assert.IsFalse(rxa.IsValid("abc.docx"));
    Assert.IsTrue(rxa.IsValid("abc.pptx"));
}
1
Brent

내 시도 :

using System.IO;

static class PathUtils
{
  public static string IsValidFullPath([NotNull] string fullPath)
  {
    if (string.IsNullOrWhiteSpace(fullPath))
      return "Path is null, empty or white space.";

    bool pathContainsInvalidChars = fullPath.IndexOfAny(Path.GetInvalidPathChars()) != -1;
    if (pathContainsInvalidChars)
      return "Path contains invalid characters.";

    string fileName = Path.GetFileName(fullPath);
    if (fileName == "")
      return "Path must contain a file name.";

    bool fileNameContainsInvalidChars = fileName.IndexOfAny(Path.GetInvalidFileNameChars()) != -1;
    if (fileNameContainsInvalidChars)
      return "File name contains invalid characters.";

    if (!Path.IsPathRooted(fullPath))
      return "The path must be absolute.";

    return "";
  }
}

Path.GetInvalidPathChars는 파일 및 디렉토리 이름에서 유효하지 않은 완전한 문자 세트를 리턴하지 않으며 물론 더 많은 미묘함이 있기 때문에 완벽하지 않습니다.

따라서이 방법을 보완 물로 사용합니다.

public static bool TestIfFileCanBeCreated([NotNull] string fullPath)
{
  if (string.IsNullOrWhiteSpace(fullPath))
    throw new ArgumentException("Value cannot be null or whitespace.", "fullPath");

  string directoryName = Path.GetDirectoryName(fullPath);
  if (directoryName != null) Directory.CreateDirectory(directoryName);
  try
  {
    using (new FileStream(fullPath, FileMode.CreateNew)) { }
    File.Delete(fullPath);
    return true;
  }
  catch (IOException)
  {
    return false;
  }
}

파일을 작성하려고 시도하고 예외가 있으면 false를 리턴합니다. 물론 파일을 만들어야하지만 가장 안전한 방법이라고 생각합니다. 또한 작성된 디렉토리는 삭제하지 않습니다.

첫 번째 방법을 사용하여 기본 유효성 검사를 수행 한 다음 경로를 사용할 때 예외를주의해서 처리 할 수도 있습니다.

1
Maxence

내 생각에,이 질문에 대한 유일한 대답은 경로를 사용하고 OS와 파일 시스템이 경로를 확인하도록하는 것입니다. 그렇지 않으면 OS와 파일 시스템이 이미 사용하고있는 모든 유효성 검사 규칙을 다시 구현하고 있으며 아마도 규칙이 변경되면 해당 규칙과 일치하도록 코드를 변경해야합니다.

0
Igor Levicki

이 확인

static bool IsValidFileName(string name)
{
    return
        !string.IsNullOrWhiteSpace(name) &&
        name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
        !Path.GetFullPath(name).StartsWith(@"\\.\");
}

예약 된 DOS 장치뿐만 아니라 유효하지 않은 문자 (<>:"/\|?* 및 ASCII 0-31)로 이름을 필터링합니다 (CON, NUL, COMx) . Path.GetFullPath와 일치하는 선행 공백과 모든 점 이름을 허용합니다. (앞 공백이있는 파일을 만드는 것이 시스템에서 성공합니다).


Windows 7에서 테스트 된 .NET Framework 4.7.1 사용.

0
Vlad

나는 누군가에게서이 아이디어를 얻었다. -누군지 몰라 OS가 무거운 작업을 수행하도록합니다.

public bool IsPathFileNameGood(string fname)
{
    bool rc = Constants.Fail;
    try
    {
        this._stream = new StreamWriter(fname, true);
        rc = Constants.Pass;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Problem opening file");
        rc = Constants.Fail;
    }
    return rc;
}
0
KenR

문자열에서 불법 문자를 확인하기위한 하나의 라이너 :

public static bool IsValidFilename(string testName) => !Regex.IsMatch(testName, "[" + Regex.Escape(new string(System.IO.Path.InvalidPathChars)) + "]");
0
Zananok

Path.GetFullPath ()를 사용하는 것이 좋습니다.

string tagetFileFullNameToBeChecked;
try
{
  Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
  // invalid chars found
}
0
Tony Sun