Recentemente, mudei um monte de MP3s de vários locais para um repositório. Eu estava construindo os novos nomes de arquivos usando as tags ID3 (obrigado, TagLib-Sharp!) E notei que estava recebendo um System.NotSupportedException
:
"O formato do caminho especificado não é suportado."
Isso foi gerado por um File.Copy()
ou outro Directory.CreateDirectory()
.
Não demorou muito para perceber que meus nomes de arquivos precisavam ser limpos. Então eu fiz o óbvio:
public static string SanitizePath_(string path, char replaceChar)
{
string dir = Path.GetDirectoryName(path);
foreach (char c in Path.GetInvalidPathChars())
dir = dir.Replace(c, replaceChar);
string name = Path.GetFileName(path);
foreach (char c in Path.GetInvalidFileNameChars())
name = name.Replace(c, replaceChar);
return dir + name;
}
Para minha surpresa, continuei recebendo exceções. Descobriu-se que ':' não está no conjunto de Path.GetInvalidPathChars()
, porque é válido em uma raiz do caminho. Suponho que isso faça sentido - mas isso deve ser um problema bastante comum. Alguém tem algum código curto que limpa um caminho? O mais completo que eu vim com isso, mas parece que é provavelmente um exagero.
// replaces invalid characters with replaceChar
public static string SanitizePath(string path, char replaceChar)
{
// construct a list of characters that can't show up in filenames.
// need to do this because ":" is not in InvalidPathChars
if (_BadChars == null)
{
_BadChars = new List<char>(Path.GetInvalidFileNameChars());
_BadChars.AddRange(Path.GetInvalidPathChars());
_BadChars = Utility.GetUnique<char>(_BadChars);
}
// remove root
string root = Path.GetPathRoot(path);
path = path.Remove(0, root.Length);
// split on the directory separator character. Need to do this
// because the separator is not valid in a filename.
List<string> parts = new List<string>(path.Split(new char[]{Path.DirectorySeparatorChar}));
// check each part to make sure it is valid.
for (int i = 0; i < parts.Count; i++)
{
string part = parts[i];
foreach (char c in _BadChars)
{
part = part.Replace(c, replaceChar);
}
parts[i] = part;
}
return root + Utility.Join(parts, Path.DirectorySeparatorChar.ToString());
}
Qualquer melhoria para tornar essa função mais rápida e menos barroca seria muito apreciada.
fonte
Respostas:
Para limpar um nome de arquivo, você pode fazer isso
fonte
GetInvalidFileNameChars
não os incluem. Ele não lança uma exceção no Windows, apenas remove-os, mas pode causar um comportamento inesperado se você estiver esperando o período. Modifiquei o regex para lidar com esse caso, fazendo.
com que seja considerado um dos caracteres inválidos se estiver no final da string.Uma solução mais curta:
fonte
Baseado na excelente resposta de Andre, mas levando em consideração o comentário de Spud sobre palavras reservadas, fiz esta versão:
E estes são meus testes de unidade
fonte
COM1
,), que também não são permitidas. Correção sugerida seria mudar o reservedWordPattern para"^{0}(\\.|$)"
eo texto de substituição para"_reservedWord_$1"
fonte
String.Concat(dirty...)
vez deJoin(String.Empty...
Estou usando o
System.IO.Path.GetInvalidFileNameChars()
método para verificar caracteres inválidos e não tenho problemas.Estou usando o seguinte código:
fonte
Eu queria manter os caracteres de alguma forma, não apenas substituí-los por um sublinhado.
Uma maneira que pensei foi substituir os personagens por personagens com aparência semelhante, que são (na minha situação), improváveis de serem usados como caracteres regulares. Então, peguei a lista de caracteres inválidos e encontrei parecidos.
A seguir, são apresentadas funções para codificar e decodificar com os itens similares.
Este código não inclui uma lista completa de todos os caracteres System.IO.Path.GetInvalidFileNameChars (). Portanto, é sua responsabilidade estender ou utilizar a substituição de sublinhado para os caracteres restantes.
Você pode selecionar suas próprias aparências. Eu usei o aplicativo Mapa de Caracteres no Windows para selecionar o meu
%windir%\system32\charmap.exe
À medida que faço os ajustes por meio da descoberta, atualizarei esse código.
fonte
!"#$%&'()*+,-./:;<=>?@{|}~
de/
largura total ou outras formas como SOLIDUS e `⁄` FRACTION SLASH que podem ser usados diretamente em nomes de arquivos sem problemasAcho que o problema é que você primeiro chama
Path.GetDirectoryName
a string incorreta. Se houver caracteres que não sejam de nome de arquivo, o .Net não poderá dizer quais partes da string são diretórios e lançamentos. Você precisa fazer comparações de strings.Supondo que apenas o nome do arquivo esteja ruim, não o caminho inteiro, tente o seguinte:
fonte
Eu tive sucesso com isso no passado.
Bom, curto e estático :-)
fonte
existem muitas soluções de trabalho aqui. apenas por uma questão de integridade, aqui está uma abordagem que não usa regex, mas usa LINQ:
Além disso, é uma solução muito curta;)
fonte
Aqui está um método eficiente de extensão de carregamento lento, baseado no código de Andre:
fonte
Seu código seria mais limpo se você anexasse o diretório e o nome do arquivo e os limpasse, em vez de higienizá-los independentemente. Quanto à limpeza do:, basta pegar o segundo caractere na string. Se for igual a "replaceechar", substitua-o por dois pontos. Como esse aplicativo é para seu próprio uso, essa solução deve ser perfeitamente suficiente.
fonte
fonte