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?
c#
windows
file
filesystems
tomash
fonte
fonte
Respostas:
Você pode obter uma lista de caracteres inválidos de
Path.GetInvalidPathChars
eGetInvalidFileNameChars
.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.
fonte
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:
<
>
:
"
/
\
|
?
*
Algumas coisas opcionais para verificar:
\?\
prefixo)\?\
(observe que o prefixo pode expandir os componentes do diretório e fazer com que ele ultrapasse o limite de 32.000)fonte
Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
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.InvalidPathChars
constante;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;Depois de saber isso, você também deve verificar diferentes formatos, por exemplo,
c:\my\drive
e\\server\share\dir\file.ext
fonte
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
Essa classe limpa nomes de arquivos e caminhos; use-o como
Aqui está o código;
fonte
Isto é o que eu uso:
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.
fonte
@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
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):
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.
fonte
Simplificando a resposta de Eugene Katz:
Ou
fonte
Path.GetInvalidFileNameChars
. Dê uma olhada aqui: referencesource.microsoft.com/#mscorlib/system/io/path.cs.289 - para cada caractere seufileName
, um clone da matriz é criado.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
fonte
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.
fonte
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.
fonte
Eu uso isso para se livrar de caracteres inválidos nos nomes de arquivos sem gerar exceções:
fonte
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
Para complementar as outras respostas, aqui estão alguns casos adicionais que você pode querer considerar.
O Excel pode ter problemas se você salvar uma pasta de trabalho em um arquivo cujo nome contenha os caracteres '[' ou ']'. Consulte http://support.microsoft.com/kb/215205 para obter detalhes.
O Sharepoint possui um conjunto adicional de restrições. Consulte http://support.microsoft.com/kb/905231 para obter detalhes.
fonte
No MSDN , eis uma lista de caracteres que não são permitidos:
fonte
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
fonte
$Boot
já existe no diretório?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)
fonte
true
.Expressões regulares são um exagero para essa situação. Você pode usar o
String.IndexOfAny()
método em combinação comPath.GetInvalidPathChars()
ePath.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.fonte
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. :-)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
Path
ficam 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.
fonte
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.
e os testes
fonte
Minha tentativa:
Isso não é perfeito porque
Path.GetInvalidPathChars
nã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:
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.
fonte
Sugiro apenas usar o Path.GetFullPath ()
fonte
Eu recebi essa ideia de alguém. - não sei quem. Deixe o sistema operacional fazer o trabalho pesado.
fonte
Essa verificação
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 comPath.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.
fonte
Um liner para verificar caracteres ilegais na cadeia de caracteres:
fonte
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.
fonte
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.
fonte