Como verifico se uma determinada string é um nome de arquivo válido / legal no Windows?

165

Quero incluir uma funcionalidade de renomeação de arquivo em lote no meu aplicativo. Um usuário pode digitar um padrão de nome de arquivo de destino e (depois de substituir alguns curingas no padrão), preciso verificar se ele será um nome de arquivo legal no Windows. Eu tentei usar expressões regulares como [a-zA-Z0-9_]+essa, mas ela não inclui muitos caracteres nacionais específicos de vários idiomas (por exemplo, tremas e assim por diante). Qual é a melhor maneira de fazer essa verificação?

tomash
fonte
Eu sugiro usar um estático compilado Regex se você estiver indo para usar qualquer uma das respostas com Regex ..
AMissico

Respostas:

100

Você pode obter uma lista de caracteres inválidos de Path.GetInvalidPathCharse GetInvalidFileNameChars.

UPD: Veja a sugestão de Steve Cooper sobre como usá-los em uma expressão regular.

UPD2: Observe que, de acordo com a seção Comentários no MSDN "Não é garantido que a matriz retornada desse método contenha o conjunto completo de caracteres inválidos nos nomes de arquivos e diretórios". A resposta fornecida por sixlettervaliables entra em mais detalhes.

Eugene Katz
fonte
11
Isso não responde à pergunta; existem muitas sequências que consistem apenas em caracteres válidos (por exemplo, "....", "CON", sequências de centenas de caracteres) que não são nomes de arquivos válidos.
Dour High Arch
31
Alguém mais desapontou que o MS não fornece função / API no nível do sistema para esse recurso, em vez de cada desenvolvedor precisar preparar sua própria solução? Querendo saber se há uma boa razão para isso ou apenas uma supervisão por parte da MS.
Thomas Nguyen
@ High Arch: Veja a resposta da pergunta "Em C #, verifique se o nome do arquivo é possivelmente válido (não que exista)". (Embora alguns caras espertos tenham fechado essa pergunta em favor desta ...)
mmmmmmmm
129

Do MSDN "Nomeando um arquivo ou diretório", aqui estão as convenções gerais sobre o que é um nome de arquivo legal no Windows:

Você pode usar qualquer caractere na página de código atual (Unicode / ANSI acima de 127), exceto:

  • < > : " / \ | ? *
  • Caracteres cujas representações inteiras são de 0 a 31 (menos que o espaço ASCII)
  • Qualquer outro caractere que o sistema de arquivos de destino não permita (por exemplo, pontos ou espaços à direita)
  • Qualquer um dos nomes do 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 (e evite AUX.txt, etc)
  • O nome do arquivo é todos os períodos

Algumas coisas opcionais para verificar:

  • Os caminhos do arquivo (incluindo o nome do arquivo) podem não ter mais de 260 caracteres (que não usam o \?\prefixo)
  • Caminhos de arquivo Unicode (incluindo o nome do arquivo) com mais de 32.000 caracteres ao usar \?\(observe que o prefixo pode expandir os componentes do diretório e fazer com que ele ultrapasse o limite de 32.000)
user7116
fonte
8
+1 por incluir nomes de arquivos reservados - eles foram perdidos nas respostas anteriores.
SqlRyan
2
"AUX" é um nome de arquivo perfeitamente utilizável se você usar a sintaxe "\\? \". É claro que os programas que não usam essa sintaxe têm problemas reais ao lidar com ela ... (Testado no XP)
user9876
9
A regex correta para todas essas condições mencionadas acima é a seguinte:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
whywhywhy
4
@whywhywhy Acho que você tem um suporte de abertura extra nesse Regex. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\. +) $) (\\ .. *)? $) | (([\\ x00 - \\ x1f \\\\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" funcionou para mim.
Wilky
4
Li o mesmo artigo mencionado nesta resposta e descobri, por meio de experimentação, que COM0 e LPT0 também não são permitidos. @dlf este trabalha com nomes de arquivos que começam com '.':^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr
67

Para .Net Frameworks anteriores à 3.5, isso deve funcionar:

A correspondência de expressões regulares deve ajudá-lo um pouco. Aqui está um trecho usando a System.IO.Path.InvalidPathCharsconstante;

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;
}

Para .Net Frameworks após a versão 3.0, isso deve funcionar:

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

A correspondência de expressões regulares deve ajudá-lo um pouco. Aqui está um trecho usando a System.IO.Path.GetInvalidPathChars()constante;

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;
}

Depois de saber isso, você também deve verificar diferentes formatos, por exemplo, c:\my\drivee\\server\share\dir\file.ext

Steve Cooper
fonte
isso não apenas testa o caminho, não o nome do arquivo?
Eugene Katz
30
string strTheseAreInvalidFileNameChars = nova string (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = new Regex ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
rao
2
Um pouco de pesquisa das pessoas faria maravilhas. Atualizei a postagem para refletir as alterações.
Erik Philips
1
O segundo pedaço de código não é compilado. "Não é possível converter de char [] para string
Paul Hunt
1
@AshkanMobayenKhiabani: InvalidPathChars está obsoleto, mas GetInvalidPathChars não.
IvanH 31/03
25

Tente usá-lo e prenda o erro. O conjunto permitido pode mudar nos sistemas de arquivos ou nas diferentes versões do Windows. Em outras palavras, se você quiser saber se o Windows gosta do nome, entregue-o e deixe-o informar.


fonte
1
Este parece ser o único que testa contra todas as restrições. Por que as outras respostas estão sendo escolhidas sobre isso?
lacuna
5
@ gap, porque nem sempre funciona. Por exemplo, tentar acessar o CON geralmente terá êxito, mesmo que não seja um arquivo real.
Antimony
4
É sempre melhor evitar a sobrecarga de memória de lançar uma exceção, sempre que possível.
Owen Blacker
2
Além disso, você pode não ter permissões para acessá-lo; por exemplo, testá-lo por escrito, mesmo que você possa lê-lo, se existir ou existir.
CodeLurker
23

Essa classe limpa nomes de arquivos e caminhos; use-o como

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

Aqui está o código;

/// <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();
    }

}
Steve Cooper
fonte
1
sua resposta poderia ser mais adequada aqui: stackoverflow.com/questions/146134/…
nawfal 12/13/13
22

Isto é o que eu uso:

    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));
    }

O primeiro padrão cria uma expressão regular que contém os nomes e caracteres de arquivo inválidos / ilegais apenas para plataformas Windows. O segundo faz o mesmo, mas garante que o nome seja legal para qualquer plataforma.

Scott Dorman
fonte
4
A expressão regular sPattern não permite arquivos iniciados com caracteres de ponto. Mas o MSDN diz "é aceitável especificar um período como o primeiro caractere de um nome. Por exemplo," .temp "". Eu iria remover "\ .. *" para fazer .gitignore nome de arquivo correto :)
yar_shukan
(Eu aprimorei gradualmente isso e excluí os comentários anteriores que deixei) Este é melhor que o regex da resposta porque permite ".gitignore", "..asdf", não permite '<' e '>' ou o iene assinar, e não permite espaço ou ponto no final (que não permite nomes consistindo apenas de pontos):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr
isso falha para todos os arquivos que testei. executá-lo para relatórios C: \ Windows \ System32 \ msxml6.dll falso.
magicandre1981
@ magicandre1981 Você precisa fornecer apenas o nome do arquivo, não o caminho completo.
Scott Dorman
ok, mas preciso verificar se o caminho completo é válido. Eu usei agora uma solução diferente.
magicandre1981
18

Um caso de esquina a ser lembrado, o que me surpreendeu quando descobri: o Windows permite caracteres de espaço iniciais em nomes de arquivos! Por exemplo, todos os nomes de arquivos são legais e distintos no Windows (menos as aspas):

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

Um exemplo disso: tenha cuidado ao escrever um código que apara os espaços em branco iniciais / finais de uma sequência de nome de arquivo.

Jon Schneider
fonte
10

Simplificando a resposta de Eugene Katz:

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

Ou

bool IsFileNameCorrect(string fileName){
    return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
tmt
fonte
Você quis dizer: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Contém (f));" ?
Jack Griffin
@JackGriffin Claro! Obrigado pela atenção.
TMT
Embora esse código seja muito agradável de ler, devemos levar em consideração as desculpas internas de Path.GetInvalidFileNameChars. Dê uma olhada aqui: referencesource.microsoft.com/#mscorlib/system/io/path.cs.289 - para cada caractere seu fileName, um clone da matriz é criado.
Piotr Zierhoffer
"DD: \\\\\ AAA ..... AAAA". Não é válido, mas para o seu código é.
Ciccio Pasticcio
8

Microsoft Windows: o kernel do Windows proíbe o uso de caracteres no intervalo 1-31 (ou seja, 0x01-0x1F) e caracteres "*: <>? \ |. Embora o NTFS permita que cada componente do caminho (diretório ou nome do arquivo) tenha 255 caracteres e caminhos com até 32767 caracteres, o kernel do Windows suporta apenas caminhos com até 259. Além disso, o Windows proíbe o uso dos nomes de dispositivo do MS-DOS AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL e PRN, bem como esses nomes com qualquer extensão (por exemplo, AUX.txt), exceto ao usar Caminhos UNC longos (por exemplo, \. \ C: \ nul.txt ou \? \ D: \ aux \ con). (De fato, CLOCK $ pode ser usado se uma extensão for fornecida.) Essas restrições se aplicam apenas ao Windows - Linux, por exemplo, permite o uso de "*: <>? \ mesmo em NTFS.

Fonte: http://en.wikipedia.org/wiki/Filename

Martin Faartoft
fonte
1
Eu posso criar um arquivo chamado "CLOCK $" muito bem. Windows 7.
rory.ap
7

Em vez de incluir explicitamente todos os caracteres possíveis, você pode fazer uma regex para verificar a presença de caracteres ilegais e reportar um erro. Idealmente, seu aplicativo deve nomear os arquivos exatamente como o usuário deseja e apenas chorar quando encontrar um erro.

ConroyP
fonte
6

A questão é: você está tentando determinar se um nome de caminho é um caminho legal do Windows ou se é legal no sistema em que o código está sendo executado. ? Eu acho que o último é mais importante, então, pessoalmente, eu provavelmente decomporia o caminho completo e tentaria usar _mkdir para criar o diretório em que o arquivo pertence e, em seguida, tentaria criar o arquivo.

Dessa forma, você sabe não apenas se o caminho contém apenas caracteres válidos do Windows, mas se ele realmente representa um caminho que pode ser gravado por esse processo.

kfh
fonte
6

Eu uso isso para se livrar de caracteres inválidos nos nomes de arquivos sem gerar exceções:

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

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

Também CON, PRN, AUX, NUL, COM # e alguns outros nunca são nomes de arquivos legais em qualquer diretório com qualquer extensão.


fonte
1
Isso é apenas metade da verdade. Você pode criar arquivos com esses nomes se chamar a versão unicode do CreateFile (prefixando o nome do arquivo com "\\? \").
Werner Henze
Esta declaração está incompleta e não tem LPT #
Thomas Weller
4

Para complementar as outras respostas, aqui estão alguns casos adicionais que você pode querer considerar.

Joe
fonte
3

No MSDN , eis uma lista de caracteres que não são permitidos:

Use quase qualquer caractere na página de código atual para um nome, incluindo caracteres Unicode e caracteres no conjunto de caracteres estendidos (128–255), exceto o seguinte:

  • Os seguintes caracteres reservados não são permitidos: <>: "/ \ |? *
  • Caracteres cujas representações inteiras estão no intervalo de zero a 31 não são permitidos.
  • Qualquer outro caractere que o sistema de arquivos de destino não permita.
Mark Biek
fonte
2

Além disso, o sistema de arquivos de destino é importante.

No NTFS, alguns arquivos não podem ser criados em diretórios específicos. Inicialização do EG $ na raiz

Dominik Weber
fonte
2
Certamente isso não é devido a uma regra de nomeação NTFS, mas apenas porque um arquivo chamado $Bootjá existe no diretório?
Christian Hayter
2

Esta é uma pergunta já respondida, mas apenas por "Outras opções", eis uma não ideal:

(não é o ideal porque o uso de Exceções como controle de fluxo é uma "coisa ruim", geralmente)

public static bool IsLegalFilename(string name)
{
    try 
    {
        var fileInfo = new FileInfo(name);
        return true;
    }
    catch
    {
        return false;
    }
}
JerKimball
fonte
Seu exemplo não funcionou para um arquivo CON (C: \ temp \ CON).
Tcbrazil
Mas 'C: \ temp \ CON' não é um nome de arquivo válido? Por que não seria?
Mark-Donohoe
@MarqueIV - não, não é válido. Leia todas as respostas e comentários acima ou tente você mesmo e veja.
Rog.ap 25/08
@Jer, "/ example" não é legal, mas seu método retorna true.
Rog.ap 25/08
Aaaah ... eu perdi a parte 'CON'. O nome em si é válido do ponto de vista da string (que é o que eu estava me referindo), mas agora vejo CON como um nome reservado, tornando-o inválido do ponto de vista do Windows. Foi mal.
Mark-Donohoe
2

Expressões regulares são um exagero para essa situação. Você pode usar o String.IndexOfAny()método em combinação com Path.GetInvalidPathChars()e Path.GetInvalidFileNameChars().

Observe também que ambos os Path.GetInvalidXXX()métodos clonam uma matriz interna e retornam o clone. Portanto, se você fizer muito isso (milhares e milhares de vezes), poderá armazenar em cache uma cópia da matriz de caracteres inválida para reutilização.

nhahtdh
fonte
2

Se você está apenas tentando verificar se uma string que contém o nome / caminho do seu arquivo possui caracteres inválidos, o método mais rápido que encontrei é usar Split()para dividir o nome do arquivo em uma matriz de partes, sempre que houver um caractere inválido. Se o resultado for apenas uma matriz de 1, não haverá caracteres inválidos. :-)

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;

Tentei executar esse e outros métodos mencionados acima em um nome de arquivo / caminho 1.000.000 de vezes no LinqPad.

Usando Split()é apenas ~ 850ms.

O uso Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")é de cerca de 6 segundos.

As expressões regulares mais complicadas Pathficam MUITO piores, assim como algumas das outras opções, como usar os vários métodos da classe para obter o nome do arquivo e permitir que a validação interna faça o trabalho (provavelmente devido à sobrecarga do tratamento de exceções).

Concedido que não é muito frequente você precisar validar 1 milhão de nomes de arquivos; portanto, uma única iteração é adequada para a maioria desses métodos. Mas ainda é bastante eficiente e eficaz se você estiver procurando apenas caracteres inválidos.

Nick Albrecht
fonte
1

muitas dessas respostas não funcionarão se o nome do arquivo for muito longo e estiver sendo executado em um ambiente anterior ao Windows 10. Da mesma forma, pense no que você quer fazer com os pontos - permitir que o início ou o final sejam tecnicamente válidos, mas podem criar problemas se você não quiser que o arquivo seja difícil de ver ou excluir, respectivamente.

Este é um atributo de validação que criei para verificar um nome de arquivo válido.

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;
}

e os testes

[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"));
}
Brent
fonte
1

Minha tentativa:

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 "";
  }
}

Isso não é perfeito porque Path.GetInvalidPathCharsnão retorna o conjunto completo de caracteres inválidos nos nomes de arquivos e diretórios e, é claro, há muito mais sutilezas.

Então, eu uso esse método como um complemento:

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;
  }
}

Ele tenta criar o arquivo e retornar false se houver uma exceção. Claro, preciso criar o arquivo, mas acho que é a maneira mais segura de fazer isso. Observe também que não estou excluindo diretórios que foram criados.

Você também pode usar o primeiro método para fazer a validação básica e, em seguida, manipular cuidadosamente as exceções quando o caminho for usado.

Maxence
fonte
0

Sugiro apenas usar o Path.GetFullPath ()

string tagetFileFullNameToBeChecked;
try
{
  Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
  // invalid chars found
}
Tony Sun
fonte
Adicione um pouco de explicação com a resposta de como essa resposta ajuda OP na fixação edição atual
ρяσѕρєя K
Consulte o documento no MSDN para AugumentExcpetion, leia: path é uma cadeia de comprimento zero, contém apenas espaço em branco ou contém um ou mais dos caracteres inválidos definidos em GetInvalidPathChars. - ou - O sistema não pôde recuperar o caminho absoluto.
Tony Sun
Em teoria (de acordo com a documentação), isso deve funcionar, embora o problema seja, pelo menos no .NET Core 3.1, não.
Michel Jansson
0

Eu recebi essa ideia de alguém. - não sei quem. Deixe o sistema operacional fazer o trabalho pesado.

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;
}
KenR
fonte
0

Essa verificação

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

filtra nomes com caracteres inválidos ( <>:"/\|?*e ASCII 0-31), bem como dispositivos DOS reservados ( CON, NUL, COMx). Permite espaços à esquerda e nomes com todos os pontos, consistentes com Path.GetFullPath. (A criação de arquivos com espaços à esquerda é bem-sucedida no meu sistema).


Usado o .NET Framework 4.7.1, testado no Windows 7.

Vlad
fonte
0

Um liner para verificar caracteres ilegais na cadeia de caracteres:

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

Na minha opinião, a única resposta adequada para essa pergunta é tentar usar o caminho e deixar que o sistema operacional e o sistema de arquivos o valide. Caso contrário, você está apenas reimplementando (e provavelmente mal) todas as regras de validação que o sistema operacional e o sistema de arquivos já usam e se essas regras forem alteradas no futuro, você precisará alterar seu código para correspondê-las.

Igor Levicki
fonte
-1

Nomes de arquivos do Windows são muito unrestrictive, então realmente ele pode até não ser que um grande problema. Os caracteres que não são permitidos pelo Windows são:

\ / : * ? " < > |

Você pode escrever facilmente uma expressão para verificar se esses caracteres estão presentes. Uma solução melhor seria tentar nomear os arquivos como o usuário desejar e alertá-los quando um nome de arquivo não grudar.

Justin Poliey
fonte
Também são proibidos caracteres <= 31.
Antimony