Windows에서 지정된 문자열이 올바른 파일 이름인지 확인하는 방법은 무엇입니까?
프로그램에 배치 파일 이름 바꾸기 기능을 포함하고 싶습니다.사용자가 대상 파일 이름 패턴을 입력할 수 있으며 (패턴에서 일부 와일드카드를 바꾼 후) Windows에서 정식 파일 이름이 될지 확인해야 합니다.저는정표사용노고려력다니습했하을현규▁express다니ion와 같은 정규 표현을 .[a-zA-Z0-9_]+
그러나 다양한 언어(예: 움라우트 등)의 국가별 문자는 많이 포함되어 있지 않습니다.그런 점검을 하는 가장 좋은 방법은 무엇입니까?
MSDN의 "파일 또는 디렉터리 이름 지정"에서 Windows 아래의 합법적인 파일 이름에 대한 일반적인 규칙은 다음과 같습니다.
다음을 제외하고 현재 코드 페이지(127 이상의 유니코드/ANSI)에 있는 모든 문자를 사용할 수 있습니다.
<
>
:
"
/
\
|
?
*
- 정수 표현이 0-31(ASCII 공백 미만)인 문자
- 대상 파일 시스템에서 허용하지 않는 다른 문자(예: 마침표 또는 공백)
- DOS 이름: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 등은 사용하지 않습니다.
- 파일 이름이 모든 마침표입니다.
선택적으로 확인해야 할 사항
- 경로이름 는할 수 (" " " " " " " " " " " " " 260자를하지 않는 것").
\?\
- 이상의 경로이름 ) 시 입니다.
\?\
는 디렉터리 요소를 할 수
및 에서 잘못된 문자 목록을 가져올 수 있습니다.
UPD: 정규식에서 사용하는 방법에 대한 Steve Cooper의 제안을 참조하십시오.
UPD2: MSDN의 비고 섹션에 따르면 "이 메서드에서 반환된 배열은 파일 및 디렉터리 이름에 잘못된 전체 문자 집합을 포함하지 않습니다."6개의 문자 값이 제공하는 답변은 더 자세히 설명됩니다.
3.5 이전 버전의 .Net Framework의 경우 다음과 같이 작동합니다.
정규 표현식 일치를 통해 방법을 찾을 수 있습니다.다음은 다음을 사용한 스니펫입니다.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;
}
3.0 이후의 .Net Framework에서는 다음과 같이 작동합니다.
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;
}
, 형식을 . 예를 , 이를알나확합야니인다해도식형른다고면▁once.c:\my\drive
그리고.\\server\share\dir\file.ext
사용해 보고 오류를 방지합니다.허용된 집합은 파일 시스템 또는 다른 버전의 Windows에서 변경될 수 있습니다.즉, Windows(윈도우)에서 이 이름을 좋아하는지 여부를 확인하려면 이름을 전달하고 알려줍니다.
이 클래스는 파일 이름 및 경로를 정리합니다. 다음과 같이 사용합니다.
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();
}
}
다음을 사용합니다.
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(윈도우)에서 파일 이름에 선두 공백 문자를 사용할 수 있다는 점입니다.예를 들어, 다음은 모두 Windows(윈도우)에서 합법적이고 고유한 파일 이름입니다(따옴표 제외).
"file.txt"
" file.txt"
" file.txt"
한 가지 이점:파일 이름 문자열에서 선행/추적 공백을 잘라내는 코드를 작성할 때는 주의하십시오.
Eugene Katz의 답변 단순화:
bool IsFileNameCorrect(string fileName){
return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}
또는
bool IsFileNameCorrect(string fileName){
return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
Microsoft Windows:Windows 커널은 1-31(예: 0x01-0x1F) 범위의 문자와 "*: < > ? \ |" 문자 사용을 금지합니다. NTFS에서는 각 경로 구성 요소(디렉토리 또는 파일 이름)의 길이가 255자이고 경로는 최대 32767자이지만 Windows 커널은 최대 259자의 경로만 지원합니다.또한 Windows에서는 예를 들어, NPT5, LPT2, LPT3, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT8, LPT9 등의 이름을 사용할 수 없습니다.\C:\nul.txt 또는 \?\D:\aux\con).(실제로 CLOCK$는 확장이 제공되는 경우 사용될 수 있습니다.)이러한 제한은 Windows - Linux에만 적용됩니다. 예를 들어 NTFS에서도 " * : < > ? \ |"를 사용할 수 있습니다.
출처: http://en.wikipedia.org/wiki/Filename
모든 가능한 문자를 명시적으로 포함하는 대신 정규식을 수행하여 잘못된 문자가 있는지 확인하고 오류를 보고할 수 있습니다.이상적으로 응용프로그램은 사용자가 원하는 대로 파일 이름을 지정해야 하며 오류가 발생한 경우에만 cryfault를 사용해야 합니다.
문제는 경로 이름이 올바른 창 경로인지 또는 코드가 실행 중인 시스템에서 합법적인지 여부를 확인하려는 것입니다.저는 후자가 더 중요하다고 생각하기 때문에 개인적으로 전체 경로를 분해하여 _mkdir를 사용하여 파일이 속한 디렉터리를 만든 다음 파일을 생성하려고 합니다.
이렇게 하면 경로에 유효한 창 문자만 포함되어 있는지 여부뿐만 아니라 실제로 이 프로세스에서 작성할 수 있는 경로를 나타낼 수 있는지도 알 수 있습니다.
이를 사용하여 예외를 던지지 않고 파일 이름에서 잘못된 문자를 제거합니다.
private static readonly Regex InvalidFileRegex = new Regex(
string.Format("[{0}]", Regex.Escape(@"<>:""/\|?*")));
public static string SanitizeFileName(string fileName)
{
return InvalidFileRegex.Replace(fileName, string.Empty);
}
또한 CON, PRN, AUX, NUL, COM# 및 기타 일부는 확장자가 지정된 디렉토리에서 합법적인 파일 이름이 아닙니다.
다른 답변을 보완하기 위해 고려해야 할 몇 가지 추가 에지 사례가 있습니다.
이름에 '[' 또는 ']' 문자가 포함된 파일에 워크북을 저장하면 Excel에 문제가 발생할 수 있습니다.자세한 내용은 http://support.microsoft.com/kb/215205 을 참조하십시오.
Sharepoint에는 전체적으로 추가적인 제한이 있습니다.자세한 내용은 http://support.microsoft.com/kb/905231 을 참조하십시오.
MSDN에서 허용되지 않는 문자 목록은 다음과 같습니다.
다음을 제외하고 유니코드 문자와 확장 문자 집합(128-255)의 문자를 포함하여 현재 코드 페이지의 거의 모든 문자를 사용하여 이름을 지정합니다.
- 예약된 다음 문자는 허용되지 않습니다. < > : " / \ | ? *
- 정수 표현의 범위가 0에서 31 사이인 문자는 허용되지 않습니다.
- 대상 파일 시스템에서 허용하지 않는 다른 문자.
이 질문은 이미 답변이 끝난 질문이지만, "기타 옵션"을 위해 이상적이지 않은 질문이 있습니다.
(일반적으로 예외를 흐름 제어로 사용하는 것은 "나쁜 일"이기 때문에 이상적이지 않습니다.)
public static bool IsLegalFilename(string name)
{
try
{
var fileInfo = new FileInfo(name);
return true;
}
catch
{
return false;
}
}
또한 대상 파일 시스템도 중요합니다.
NTFS에서는 일부 파일을 특정 디렉터리에 만들 수 없습니다.루트 $Boot
정규 표현식은 이 상황에 대해 과잉 살상입니다.당신은 할 수 .String.IndexOfAny()
와 Path.GetInvalidPathChars()
그리고.Path.GetInvalidFileNameChars()
.
또한 두 가지 모두에 유의하십시오.Path.GetInvalidXXX()
메소드는 내부 어레이를 복제하고 복제본을 반환합니다.따라서 이 작업을 자주(수천 번, 수천 번) 수행할 경우 잘못된 Chars 어레이의 복사본을 캐슁하여 재사용할 수 있습니다.
파일 이름이 너무 길고 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"));
}
이름문자가 , 은 파일경이/로를문잘문못에된방은있확경법빠가우는른을 사용하는 입니다.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
클래스는 파일 이름을 가져오고 내부 검증이 작업을 수행하도록 합니다(대부분 예외 처리의 오버헤드로 인해).
100만 개의 파일 이름을 검증해야 하는 경우가 드물기 때문에 대부분의 방법에 대해 한 번만 반복해도 좋습니다.그러나 유효하지 않은 문자만 찾는 경우에는 여전히 상당히 효율적이고 효과적입니다.
이 아이디어는 누군가에게서 얻은 것입니다. - 누군지 모르겠어요.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;
}
Windows 파일 이름은 매우 제한적이므로 문제가 되지 않을 수도 있습니다.Windows에서 허용되지 않는 문자는 다음과 같습니다.
\ / : * ? " < > |
당신은 그 문자들이 있는지 확인하기 위해 쉽게 표현을 쓸 수 있습니다.더 나은 해결책은 사용자가 원하는 대로 파일 이름을 지정하고 파일 이름이 고정되지 않을 때 알림을 표시하는 것입니다.
그냥 경로를 사용하는 것이 좋습니다.전체 경로 가져오기()
string tagetFileFullNameToBeChecked;
try
{
Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
// invalid chars found
}
내 시도:
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를 반환하려고 합니다.물론 파일을 만들어야 하지만 그렇게 하는 것이 가장 안전할 것 같습니다.작성된 디렉토리는 삭제하지 않습니다.
또한 첫 번째 방법을 사용하여 기본 검증을 수행한 다음 경로가 사용될 때 예외를 신중하게 처리할 수 있습니다.
이 수표
static bool IsValidFileName(string name)
{
return
!string.IsNullOrWhiteSpace(name) &&
name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
!Path.GetFullPath(name).StartsWith(@"\\.\");
}
문자가 (" 못된문자니다필합잘링터을이름있는"().<>:"/\|?*
(및된 도스 장치ASCII 0-31), 도스 도스 도스 도스 도스 도스 도스 도스 도스 도스 ()CON
,NUL
,COMx
)와 점 이름을 Path.GetFullPath
(앞에 공백이 있는 파일을 만드는 데 성공했습니다.)
윈도우즈 7에서 테스트된 .NET Framework 4.7.1 사용.
문자열에서 잘못된 문자를 확인하기 위한 하나의 라이너:
public static bool IsValidFilename(string testName) => !Regex.IsMatch(testName, "[" + Regex.Escape(new string(System.IO.Path.InvalidPathChars)) + "]");
제 생각에 이 질문에 대한 유일한 적절한 대답은 경로를 사용하여 OS와 파일 시스템이 검증하도록 하는 것입니다.그렇지 않으면 OS와 파일 시스템이 이미 사용하고 있는 모든 유효성 검사 규칙을 다시 구현하는 것이며, 향후 이러한 규칙이 변경되면 코드를 이에 맞게 변경해야 합니다.
언급URL : https://stackoverflow.com/questions/62771/how-do-i-check-if-a-given-string-is-a-legal-valid-file-name-under-windows
'programing' 카테고리의 다른 글
MongoDB collection.find()에 대한 콜백을 받는 방법 (0) | 2023.05.13 |
---|---|
일부 문자열로 접히는 hrefend 선택 (0) | 2023.05.13 |
코드가 DEBUG/릴리스 빌드에서 실행 중인지 여부를 확인하는 방법은 무엇입니까? (0) | 2023.05.13 |
HTML 형식의 전자 메일을 보내는 방법은 무엇입니까? (0) | 2023.05.13 |
쿼리 키의 MongoDB 와일드카드 (0) | 2023.05.13 |