Я хочу включить в свое приложение функцию переименования пакетного файла. Пользователь может ввести шаблон имени файла назначения и (после замены некоторых подстановочных знаков в шаблоне) мне нужно проверить, будет ли оно допустимым именем файла в Windows. Я пробовал использовать регулярное выражение вроде [a-zA-Z0-9_]+, но оно не включает много национальных символов из разных языков (например, умляуты и т. д.). Как лучше всего сделать такую проверку?





Вместо того, чтобы явно включать все возможные символы, вы можете использовать регулярное выражение, чтобы проверить наличие недопустимых символов и затем сообщить об ошибке. В идеале ваше приложение должно называть файлы точно так, как хочет пользователь, и кричать только о том, что обнаруживает ошибку.
Вот список недопустимых символов из MSDN:
Use almost any character in the current code page for a name, including Unicode characters and characters in the extended character set (128–255), except for the following:
- The following reserved characters are not allowed: < > : " / \ | ? *
- Characters whose integer representations are in the range from zero through 31 are not allowed.
- Any other character that the target file system does not allow.
Вы можете получить список недопустимых символов из Path.GetInvalidPathChars и GetInvalidFileNameChars.
UPD: См. Предложение Стива Купера о том, как использовать их в регулярном выражении.
UPD2: Обратите внимание, что согласно разделу «Примечания» в MSDN «Массив, возвращаемый этим методом, не гарантирует, что он будет содержать полный набор символов, которые недопустимы в именах файлов и каталогов». Ответ предоставлен sixlettervaliables входит в более подробную информацию.
Это не отвечает на вопрос; есть много строк, состоящих только из допустимых символов (например, «....», «CON», строки длиной в сотни символов), которые не являются допустимыми именами файлов.
Кто-нибудь еще разочарован тем, что MS не предоставляет функцию / API системного уровня для этой возможности, вместо того, чтобы каждый разработчик готовил свое собственное решение? Интересно, есть ли для этого веская причина или просто недосмотр со стороны РС.
@High Arch: см. Ответ на вопрос «В C# проверьте, что имя файла является допустимым возможно (а не то, что оно существует)». (Хотя некоторые умники закрыли этот вопрос в пользу этого ...)
Имена файлов Windows довольно неограниченны, так что на самом деле это может даже не быть проблемой который. В Windows запрещены следующие символы:
\ / : * ? " < > |
Вы можете легко написать выражение, чтобы проверить, присутствуют ли эти символы. Однако лучшим решением было бы попытаться называть файлы так, как хочет пользователь, и предупреждать их, когда имя файла не сохраняется.
Также запрещены символы <= 31.
Также CON, PRN, AUX, NUL, COM # и некоторые другие никогда не являются допустимыми именами файлов в любом каталоге с любым расширением.
Это только половина правды. Вы можете создавать файлы с этими именами, если вызываете unicode-версию CreateFile (добавляя к имени файла префикс «\\? \»).
Это заявление является неполным и пропускает LPT #
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 - Linux, например, позволяет использовать "*: <>?" \ | даже в NTFS.
Источник: http://en.wikipedia.org/wiki/Filename
Я могу создать файл с именем «CLOCK $». Windows 7.
Для .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.
Разве это не проверяет только путь, а не имя файла?
строка strTheseAreInvalidFileNameChars = новая строка (System.IO.Path.GetInvalidFileNameChars ()); Регулярное выражение regFixFileName = новое регулярное выражение ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
Небольшое исследование людей творит чудеса. Я обновил сообщение, чтобы отразить изменения.
2-й фрагмент кода не компилируется. "Невозможно преобразовать из char [] в строку
+1 для кода, но замените Path.GetInvalidPathChars() на Path.GetInvalidFileNameChars(), так как Path.GetInvalidPathChars() сейчас устарел
@AshkanMobayenKhiabani: InvalidPathChars устарел, а GetInvalidPathChars - нет.
Вопрос в том, пытаетесь ли вы определить, является ли имя пути допустимым путем Windows или разрешено в системе, в которой выполняется код.? Я думаю, что последнее более важно, поэтому лично я бы, вероятно, разложил полный путь и попытался использовать _mkdir для создания каталога, в котором находится файл, а затем попытаться создать файл.
Таким образом, вы узнаете не только то, содержит ли путь только допустимые символы Windows, но и действительно ли он представляет путь, который может быть записан этим процессом.
Из MSDN "Присвоение имени файлу или каталогу" здесь приведены общие соглашения о том, что такое допустимое имя файла в Windows:
Вы можете использовать любой символ в текущей кодовой странице (Unicode / ANSI выше 127), за исключением:
<>:"/\|?*Некоторые необязательные вещи для проверки:
\?\).\?\ (обратите внимание, что префикс может расширить компоненты каталога и привести к превышению лимита в 32000)+1 за включение зарезервированных имен файлов - они были пропущены в предыдущих ответах.
«AUX» - это имя файла, которое можно использовать, если вы используете синтаксис «\\? \». Конечно, программы, которые не используют этот синтаксис, имеют реальные проблемы с этим ... (Проверено на XP)
Правильное регулярное выражение для всех этих условий, упомянутых выше, выглядит следующим образом: Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\.+)$)(\..*)?$)|(([\x00-\x1f\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
@whywhywhy Я думаю, у вас есть дополнительная открывающая скобка в этом регулярном выражении. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\. +) $) (\\ .. *)? $) | (([ \\ x00 - \\ x1f \\\\? *: \ "; | / <>]) +) | ([\\.] +)" работал у меня.
Уилки: ваше регулярное выражение также удалит "." в пределах имени файла, которые совершенно верны.
Это лучше: (^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\.+)$)(\..*)?$)|(([\\x00-\x1f\\?*:\"|/<>])+)|(^([\.]+))
Все приведенные выше регулярные выражения отклоняют имена файлов, начинающиеся с '.', Что разрешено ОС.
Зависит от того, как вы определяете «разрешено». Окна разрешает имена файлов, начинающиеся с точки, но Исследователь не позволяет вам называть файл как таковой, если он также не имеет расширения. Например, .foo не разрешен, но .foo.bar разрешен.
Я прочитал ту же статью, упомянутую в этом ответе, и путем экспериментов обнаружил, что COM0 и LPT0 также не разрешены. @dlf работает с именами файлов, начинающимися с '.': ^(?!^(?:PRN|AUX|CLOCK$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\?*:\";|/<>]+(?<![\s.])$
Есть ли библиотека, которая обрабатывает все эти случаи?
@papaiatis - "ЧАСЫ $" мне подходят. Windows 7.
Кстати, правило «имя файла - все точки» уже содержится в «правиле конечных точек или пробелов»
Попробуйте использовать это и ловите ошибку. Разрешенный набор может меняться в зависимости от файловой системы или разных версий Windows. Другими словами, если вы хотите знать, нравится ли Windows это имя, передайте ему имя и позвольте ему сказать вам.
Кажется, это единственный, который проверяет все ограничения. Почему вместо этого выбираются другие ответы?
@gap, потому что это не всегда работает. Например, попытка доступа к CON часто бывает успешной, даже если это не настоящий файл.
Тем не менее, всегда лучше избегать накладных расходов памяти на выброс исключения, где это возможно.
Кроме того, у вас может не быть разрешений на доступ к нему; например чтобы проверить это письменно, даже если вы можете прочитать его, если он существует или будет существовать.
Вот что я использую:
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. Второй делает то же самое, но гарантирует, что имя допустимо для любой платформы.
Регулярное выражение sPattern не разрешает файлы, начинающиеся с символа точки. Но MSDN говорит "допустимо указывать точку в качестве первого символа имени. Например," .temp "". Я бы удалил "\ .. *", чтобы имя файла .gitignore было правильным :)
(Я постепенно улучшал это и удалял предыдущие комментарии, которые я оставил) Этот лучше, чем регулярное выражение ответа, потому что он позволяет ".gitignore", "..asdf", не позволяет '<' и '>' или иену знак и не допускает пробелов или точек в конце (что запрещает имена, состоящие только из точек): @"^(?!(?:PRN|AUX|CLOCK$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\?*:\"";|/<>]+(?<![\s.])$"
это не подходит для всех файлов, которые я тестировал. запуск его для C: \ Windows \ System32 \ msxml6.dll сообщает false.
@ magicandre1981 Вам нужно указать только имя файла, а не полный путь.
хорошо, но мне нужно проверить, действителен ли полный путь. Я использовал сейчас другое решение.
Ваш шаблон не работает на .foo.bar.
Это также позволяет < и >.
Регулярные выражения в этой ситуации излишни. Вы можете использовать метод String.IndexOfAny() в сочетании с Path.GetInvalidPathChars() и Path.GetInvalidFileNameChars().
Также обратите внимание, что оба метода Path.GetInvalidXXX() клонируют внутренний массив и возвращают клон. Поэтому, если вы собираетесь делать это много (тысячи и тысячи раз), вы можете кэшировать копию недопустимого массива символов для повторного использования.
Следует иметь в виду один угловой случай, который удивил меня, когда я впервые об этом узнал: Windows позволяет использовать пробелы в именах файлов! Например, все нижеприведенные имена являются законными и разными именами файлов в Windows (без кавычек):
"file.txt"
" file.txt"
" file.txt"
Один вывод из этого: будьте осторожны при написании кода, который удаляет начальные / конечные пробелы из строки имени файла.
Этот класс очищает имена файлов и пути; используйте это как
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();
}
}
ваш ответ мог бы быть лучше здесь: stackoverflow.com/questions/146134/…
Также важна файловая система назначения.
В NTFS некоторые файлы не могут быть созданы в определенных каталогах. НАПРИМЕР. $ Boot в корне
Конечно, это не из-за правила именования NTFS, а просто потому, что файл с именем $Boot уже существует в каталоге?
Чтобы дополнить другие ответы, вот несколько дополнительных крайних случаев, которые вы, возможно, захотите рассмотреть.
У Excel могут возникнуть проблемы, если вы сохраните книгу в файле, имя которого содержит символы '[' или ']'. Подробнее см. http://support.microsoft.com/kb/215205.
У Sharepoint есть целый дополнительный набор ограничений. Подробнее см. http://support.microsoft.com/kb/905231.
На этот вопрос уже дан ответ, но просто ради «других вариантов» вот неидеальный вопрос:
(неидеально, потому что использование исключений в качестве управления потоком, как правило, является "плохой вещью")
public static bool IsLegalFilename(string name)
{
try
{
var fileInfo = new FileInfo(name);
return true;
}
catch
{
return false;
}
}
Ваш пример не работал с файлом CON (C: \ temp \ CON).
Но разве 'C: \ temp \ CON' не является допустимым именем файла? Почему бы и нет?
@MarqueIV - нет, не действует. Прочтите все ответы и комментарии выше или попробуйте сами и убедитесь.
@Jer, "/ example" недопустимы, но ваш метод возвращает true.
Аааа ... Я пропустил часть "ПРОТИВ". Само имя действительно с точки зрения нить (это то, что я имел в виду), но теперь я вижу, что CON - зарезервированное имя, что делает его недействительным с точки зрения Windows. Виноват.
Я использую это, чтобы избавиться от недопустимых символов в именах файлов без исключения исключений:
private static readonly Regex InvalidFileRegex = new Regex(
string.Format("[{0}]", Regex.Escape(@"<>:""/\|?*")));
public static string SanitizeFileName(string fileName)
{
return InvalidFileRegex.Replace(fileName, string.Empty);
}
Я предлагаю просто использовать Path.GetFullPath ()
string tagetFileFullNameToBeChecked;
try
{
Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
// invalid chars found
}
Добавьте объяснение с ответом на то, как этот ответ помогает OP в устранении текущей проблемы
См. Документ в MSDN для AugumentExcpetion, он гласит: path является строкой нулевой длины, содержит только пробелы или содержит один или несколько недопустимых символов, определенных в GetInvalidPathChars. -или- Системе не удалось получить абсолютный путь.
Теоретически (согласно документам) это должно работать, проблема в том, что, по крайней мере, в .NET Core 3.1 это не так.
Упрощая ответ Юджина Каца:
bool IsFileNameCorrect(string fileName){
return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}
Или же
bool IsFileNameCorrect(string fileName){
return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
Возможно, вы имели в виду: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Contains (f)) ;" ?
@JackGriffin Конечно! Спасибо за внимание.
Хотя этот код очень приятно читать, мы должны принять во внимание жалкие внутренние детали Path.GetInvalidFileNameChars. Взгляните сюда: linksource.microsoft.com/#mscorlib/system/io/path.cs,28 9 - для каждого символа вашего fileName создается клон массива.
«ДД: \\\\\ AAA ..... AAAA». Недействительно, но для вашего кода это так.
многие из этих ответов не будут работать, если имя файла слишком длинное и работает в среде до 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;
Я пробовал запустить этот и другие методы, упомянутые выше, для имени файла / пути 1000000 раз в LinqPad.
Использование Split() составляет всего ~ 850 мс.
Использование Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]") занимает около 6 секунд.
Более сложные регулярные выражения выглядят НАМНОГО хуже, как и некоторые другие варианты, такие как использование различных методов класса Path для получения имени файла и их внутренней проверки выполнения работы (скорее всего, из-за накладных расходов на обработку исключений).
Конечно, не очень часто вам нужно проверять 1 миллион имен файлов, поэтому для большинства этих методов достаточно одной итерации. Но он по-прежнему довольно эффективен и действенен, если вы ищете только недопустимые символы.
Моя попытка:
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 в случае исключения. Конечно, мне нужно создать файл, но я думаю, что это самый безопасный способ сделать это. Также обратите внимание, что я не удаляю созданные каталоги.
Вы также можете использовать первый метод для выполнения базовой проверки, а затем тщательно обрабатывать исключения при использовании пути.
Я получил эту идею от кого-то. - не знаю кто. Пусть ОС сделает всю тяжелую работу.
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;
}
Это должен быть принятый ответ (за возможным исключением сетевых путей).
Эта проверка
static bool IsValidFileName(string name)
{
return
!string.IsNullOrWhiteSpace(name) &&
name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
!Path.GetFullPath(name).StartsWith(@"\.\");
}
отфильтровывает имена с недопустимыми символами (<>:"/\|?* и ASCII 0-31), а также зарезервированные устройства DOS (CON, NUL, COMx). Он позволяет использовать начальные пробелы и имена, состоящие из точек, в соответствии с Path.GetFullPath. (Создание файла с ведущими пробелами в моей системе выполняется успешно).
Использовал .NET Framework 4.7.1, протестирован на Windows 7.
Один лайнер для проверки незаконных символов в строке:
public static bool IsValidFilename(string testName) => !Regex.IsMatch(testName, "[" + Regex.Escape(new string(System.IO.Path.InvalidPathChars)) + "]");
На мой взгляд, единственный правильный ответ на этот вопрос - попытаться использовать путь и позволить ОС и файловой системе проверить его. В противном случае вы просто повторно реализуете (и, вероятно, плохо) все правила проверки, которые уже используют ОС и файловая система, и если эти правила будут изменены в будущем, вам придется изменить свой код, чтобы он соответствовал им.
Я предлагаю использовать статическое скомпилированное Regex, если вы собираетесь использовать какой-либо из ответов с Regex ..