Как проверить, является ли данная строка допустимым / допустимым именем файла в Windows? - PullRequest
154 голосов
/ 15 сентября 2008

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

Ответы [ 26 ]

6 голосов
/ 25 февраля 2013

Я использую это, чтобы избавиться от недопустимых символов в именах файлов без исключения:

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

public static string SanitizeFileName(string fileName)
{
    return InvalidFileRegex.Replace(fileName, string.Empty);
}
5 голосов
/ 15 сентября 2008

Также CON, PRN, AUX, NUL, COM # и некоторые другие никогда не являются допустимыми именами файлов в любом каталоге с любым расширением.

5 голосов
/ 15 сентября 2008

Вопрос в том, пытаетесь ли вы определить, является ли имя пути допустимым путем Windows или оно является допустимым в системе, где выполняется код. ? Я думаю, что последнее более важно, поэтому лично я, вероятно, разложил бы полный путь и попытался бы использовать _mkdir для создания каталога, к которому принадлежит файл, а затем попытаться создать файл.

Таким образом, вы знаете не только, содержит ли путь только допустимые символы Windows, но и действительно ли он представляет путь, который может быть записан этим процессом.

4 голосов
/ 19 января 2012

В дополнение к другим ответам, вот пара дополнительных крайних случаев, которые вы, возможно, захотите рассмотреть.

  • В Excel могут возникнуть проблемы, если вы сохраните книгу в файл, имя которого содержит символы «[» или «]». Подробнее см. http://support.microsoft.com/kb/215205.

  • Sharepoint имеет целый дополнительный набор ограничений. Подробнее см. http://support.microsoft.com/kb/905231.

3 голосов
/ 15 сентября 2008

С MSDN , вот список символов, которые не допускаются:

Используйте почти любой символ в текущей кодовой странице для имени, включая символы Юникода и символы в расширенном наборе символов (128–255), за исключением следующего:

  • Следующие зарезервированные символы недопустимы: <>: "/ \ |? *
  • Символы, чьи целочисленные представления находятся в диапазоне от нуля до 31, не допускаются.
  • Любой другой символ, который не разрешен целевой файловой системой.
2 голосов
/ 31 декабря 2012

Это вопрос, на который уже дан ответ, но только ради «других вариантов», вот неидеальный:

(неидеально, потому что использование исключений в качестве управления потоком - это, как правило, "плохая вещь")

public static bool IsLegalFilename(string name)
{
    try 
    {
        var fileInfo = new FileInfo(name);
        return true;
    }
    catch
    {
        return false;
    }
}
2 голосов
/ 24 августа 2010

Также важна файловая система назначения.

В NTFS некоторые файлы не могут быть созданы в определенных каталогах. НАПРИМЕР. $ Boot в корне

2 голосов
/ 15 сентября 2008

Регулярные выражения излишни для этой ситуации. Вы можете использовать метод String.IndexOfAny() в сочетании с Path.GetInvalidPathChars() и Path.GetInvalidFileNameChars().

Также обратите внимание, что оба метода Path.GetInvalidXXX() клонируют внутренний массив и возвращают клон. Поэтому, если вы собираетесь делать это много раз (тысячи и тысячи раз), вы можете кэшировать копию недопустимого массива chars для повторного использования.

1 голос
/ 30 сентября 2017

Моя попытка:

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 голос
/ 25 августа 2017

Если вы пытаетесь проверить, не содержит ли строка, содержащая ваше имя / путь к файлу, недопустимые символы, самый быстрый способ, который я нашел, - это использовать 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;

Я пытался запустить этот и другие методы, упомянутые выше, для имени файла / пути 1 000 000 раз в LinqPad.

Использование Split() составляет всего ~ 850 мс.

Использование Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]") составляет около 6 секунд.

Более сложные регулярные выражения справедливо НАМНОГО хуже, как и некоторые другие опции, такие как использование различных методов класса Path для получения имени файла и выполнения их внутренней проверки (скорее всего из-за накладных расходов). обработки исключений).

Конечно, вам не очень часто нужно проверять 1 миллион имен файлов, так что в любом случае для большинства этих методов подходит одна итерация. Но это все еще довольно эффективно и эффективно, если вы ищете только недопустимые символы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...