Verifique se um caminho é válido

110

Estou apenas pensando: estou procurando uma maneira de validar se um determinado caminho é válido. (Observação: não quero verificar se um arquivo existe! Só quero comprovar a validade do caminho - então, se é possível que exista um arquivo no local) .

O problema é que não consigo encontrar nada na API .Net. Devido aos vários formatos e locais que o Windows suporta, prefiro usar algo nativo do MS.

Uma vez que a função deve ser capaz de verificar:

  • Caminhos Relativos (./)
  • Caminhos absolutos (c: \ tmp)
  • UNC-Pathes (\ some-pc \ c $)
  • Limitações de NTFS como o caminho completo de 1024 caracteres - Se não me engano, exceder o caminho tornará um arquivo inacessível para muitas funções internas do Windows. Renomear com o Explorer ainda funciona
  • Caminhos de GUID de volume: "\? \ Volume {GUID} \ somefile.foo

Alguém tem uma função assim?

Tobias Boschek
fonte

Respostas:

58

Experimente Uri.IsWellFormedUriString():

  • A string não tem escape correto.

    http://www.example.com/path???/file name
  • A string é um Uri absoluto que representa um arquivo implícito Uri.

    c:\\directory\filename
  • A string é um URI absoluto sem uma barra antes do caminho.

    file://c:/directory/filename
  • A string contém barras invertidas sem escape, mesmo se forem tratadas como barras.

    http:\\host/path/file
  • A string representa um Uri absoluto hierárquico e não contém ": //".

    www.example.com/path/file
  • O analisador para o Uri.Scheme indica que a string original não estava bem formada.

    The example depends on the scheme of the URI.
Abatishchev
fonte
9
Isso retorna falso para @"foo\bar\baz", que é um caminho relativo perfeitamente válido ...
Thomas Levesque,
5
Thomas: Qual UriKind você especificou? Você pode usar Absolute, Relative ou AbsoluteOrRelative.
Dan Gøran Lunde
1
Mesmo com UriKind como Relative ou AbsoluteOrRelative, não funcionou para caminhos relativos como Thomas mencionou. Acabei usando a resposta de Patko, e ela funciona para meus objetivos.
JohnnyM de
1
Descobri que um caminho como \\ computerName \ Dir Name With Spaces \ fileName lança uma exceção ao usar IsWellFormedUriString (ao contrário da minha expectativa inicial), porque os espaços não estão devidamente codificados. Descobri que poderia apenas usar o construtor Uri (string) como minha validação, assim, não tendo que codificar corretamente a string antes de validar.
quintessencial 5 de
3
Retorna falso em um caminho de arquivo perfeitamente correto.
Evgeni Petrov
7
private bool IsValidPath(string path)
{
    Regex driveCheck = new Regex(@"^[a-zA-Z]:\\$");
    if (!driveCheck.IsMatch(path.Substring(0, 3))) return false;
    string strTheseAreInvalidFileNameChars = new string(Path.GetInvalidPathChars());
    strTheseAreInvalidFileNameChars += @":/?*" + "\"";
    Regex containsABadCharacter = new Regex("[" + Regex.Escape(strTheseAreInvalidFileNameChars) + "]");
    if (containsABadCharacter.IsMatch(path.Substring(3, path.Length - 3)))
        return false;

    DirectoryInfo dir = new DirectoryInfo(Path.GetFullPath(path));
    if (!dir.Exists)
        dir.Create();
    return true;
}
Alex Jolig
fonte
7

Não tive problemas com o código abaixo. (Caminhos relativos devem começar com '/' ou '\').

private bool IsValidPath(string path, bool allowRelativePaths = false)
{
    bool isValid = true;

    try
    {
        string fullPath = Path.GetFullPath(path);

        if (allowRelativePaths)
        {
            isValid = Path.IsPathRooted(path);
        }
        else
        {
            string root = Path.GetPathRoot(path);
            isValid = string.IsNullOrEmpty(root.Trim(new char[] { '\\', '/' })) == false;
        }
    }
    catch(Exception ex)
    {
        isValid = false;
    }

    return isValid;
}

Por exemplo, eles retornariam falso:

IsValidPath("C:/abc*d");
IsValidPath("C:/abc?d");
IsValidPath("C:/abc\"d");
IsValidPath("C:/abc<d");
IsValidPath("C:/abc>d");
IsValidPath("C:/abc|d");
IsValidPath("C:/abc:d");
IsValidPath("");
IsValidPath("./abc");
IsValidPath("./abc", true);
IsValidPath("/abc");
IsValidPath("abc");
IsValidPath("abc", true);

E estes retornariam verdadeiros:

IsValidPath(@"C:\\abc");
IsValidPath(@"F:\FILES\");
IsValidPath(@"C:\\abc.docx\\defg.docx");
IsValidPath(@"C:/abc/defg");
IsValidPath(@"C:\\\//\/\\/\\\/abc/\/\/\/\///\\\//\defg");
IsValidPath(@"C:/abc/def~`!@#$%^&()_-+={[}];',.g");
IsValidPath(@"C:\\\\\abc////////defg");
IsValidPath(@"/abc", true);
IsValidPath(@"\abc", true);
Dao Seeker
fonte
3

Você pode tentar este código:

try
{
  Path.GetDirectoryName(myPath);
}
catch
{
  // Path is not valid
}

Não tenho certeza se cobre todos os casos ...

Nimrod
fonte
2

O mais perto que cheguei foi tentando criá-lo e vendo se dá certo.

Martijn
fonte
2

Existem muitas soluções boas aqui, mas como nenhuma delas verifique se o caminho está enraizado em uma unidade existente, aqui está outra:

private bool IsValidPath(string path)
{
    // Check if the path is rooted in a driver
    if (path.Length < 3) return false;
    Regex driveCheck = new Regex(@"^[a-zA-Z]:\\$");
    if (!driveCheck.IsMatch(path.Substring(0, 3))) return false;

    // Check if such driver exists
    IEnumerable<string> allMachineDrivers = DriveInfo.GetDrives().Select(drive => drive.Name);
    if (!allMachineDrivers.Contains(path.Substring(0, 3))) return false;

    // Check if the rest of the path is valid
    string InvalidFileNameChars = new string(Path.GetInvalidPathChars());
    InvalidFileNameChars += @":/?*" + "\"";
    Regex containsABadCharacter = new Regex("[" + Regex.Escape(InvalidFileNameChars) + "]");
    if (containsABadCharacter.IsMatch(path.Substring(3, path.Length - 3)))
        return false;
    if (path[path.Length - 1] == '.') return false;

    return true;
}

Esta solução não leva em conta os caminhos relativos.

Gark Garcia
fonte
1

Obtenha os caracteres inválidos de System.IO.Path.GetInvalidPathChars();e verifique se sua string (caminho do diretório) os contém ou não.

Umesh CHILAKA
fonte
3
Isso não é totalmente válido. "C: \ new.folder" é válido enquanto "C: \ newfolder." não é. '.' é um caractere válido para caminhos / nomes de arquivos, mas não no final do uri.
claudekennilol
0

Directory.Exists?

ferreiro
fonte
4
"[...] não quero verificar se um arquivo existe!"
Stefan
3
Esse teste para o diretório existente, não para ser um caminho válido (onde um pode existir, ou ser criado, dados os privilégios adequados)
Martijn
3
@Jason - Não verifica o arquivo, apenas a pasta que o contém.
markpsmith
8
mas um caminho de diretório válido ainda não pode existir.
Stefan
-2
private bool IsValidPath(string path)
{
    Regex driveCheck = new Regex(@"^[a-zA-Z]:\\$");

    if (string.IsNullOrWhiteSpace(path) || path.Length < 3)
    {
        return false;
    }

    if (!driveCheck.IsMatch(path.Substring(0, 3)))
    {
        return false;
    }

    var x1 = (path.Substring(3, path.Length - 3));
    string strTheseAreInvalidFileNameChars = new string(Path.GetInvalidPathChars());
    strTheseAreInvalidFileNameChars += @":?*";
    Regex containsABadCharacter = new Regex("[" + Regex.Escape(strTheseAreInvalidFileNameChars) + "]");

    if (containsABadCharacter.IsMatch(path.Substring(3, path.Length - 3)))
    {
        return false;
    }

    var driveLetterWithColonAndSlash = Path.GetPathRoot(path);

    if (!DriveInfo.GetDrives().Any(x => x.Name == driveLetterWithColonAndSlash))
    {
        return false;
    }

    return true;
}
Ghislain Zabatio
fonte
1
qual é o propósito de x1?
JayJay
-3

Basta usar

if (System.IO.Directory.Exists(path))
{
    ...
}
Mahdi Astanei
fonte
-4

Você pode tentar usar Path.IsPathRooted () em combinação com Path.GetInvalidFileNameChars () para se certificar de que o caminho está parcialmente correto.

Alen Milakovic
fonte