Sprawdź, czy podano pełną ścieżkę

104

Czy istnieje metoda sprawdzenia, czy podana ścieżka jest pełną ścieżką? Teraz robię to:

if (template.Contains(":\\")) //full path already given
{
}
else //calculate the path from local assembly
{
}

Ale czy musi być bardziej elegancki sposób na sprawdzenie tego?

hs2d
źródło

Odpowiedzi:

141

Spróbuj użyć System.IO.Path.IsPathRooted? Wraca również truedla ścieżek bezwzględnych.

System.IO.Path.IsPathRooted(@"c:\foo"); // true
System.IO.Path.IsPathRooted(@"\foo"); // true
System.IO.Path.IsPathRooted("foo"); // false

System.IO.Path.IsPathRooted(@"c:1\foo"); // surprisingly also true
System.IO.Path.GetFullPath(@"c:1\foo");// returns "[current working directory]\1\foo"
detaylor
źródło
14
Dlaczego drugi przykład to ścieżka absolutna?
om471987
4
Druga ścieżka nie jest absolutna, ale jest zakorzeniona. Wiodący ukośnik wskazuje katalog główny systemu.
detaylor
3
@SmirkinGherkin, więc jaka jest różnica między ścieżką zakorzenioną a absolutną?
Jason Axelson
1
Zobacz moją odpowiedź ( stackoverflow.com/a/35046453/704808 ), aby uzyskać alternatywę, która zapewnia pełną ścieżkę, zachowując zalety IsPathRooted: unikania dostępu do systemu plików lub zgłaszania wyjątków w przypadku nieprawidłowych danych wejściowych.
jaz
1
@daniel, IIRC został dołączony, aby pokazać, że ścieżka nie musi być prawidłową ścieżką, aby z nią korzystać, z IsPathRootedpewnością nie była to nic znaczącego. GetFullPathLinia została włączona tak, że ścieżka jest oceniany można zaobserwować
detaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

Powyższy warunek:

  • nie wymaga uprawnień do systemu plików
  • zwraca falsew większości przypadków, gdy format pathjest nieprawidłowy (zamiast zgłaszać wyjątek)
  • zwraca truetylko wtedy, gdy pathzawiera objętość

W scenariuszach takich jak ten, który przedstawił PO, może zatem być bardziej odpowiedni niż warunki z wcześniejszych odpowiedzi. W przeciwieństwie do powyższego warunku:

  • path == System.IO.Path.GetFullPath(path)zgłasza wyjątki zamiast zwracać falsew następujących scenariuszach:
    • Rozmówca nie ma wymaganych uprawnień
    • System nie mógł pobrać ścieżki bezwzględnej
    • ścieżka zawiera dwukropek („:”), który nie jest częścią identyfikatora woluminu
    • Określona ścieżka, nazwa pliku lub oba te elementy przekraczają maksymalną długość zdefiniowaną przez system
  • System.IO.Path.IsPathRooted(path)zwraca, truejeśli pathzaczyna się od pojedynczego separatora katalogu.

Wreszcie, oto metoda, która obejmuje powyższy warunek, a także wyklucza pozostałe możliwe wyjątki:

public static bool IsFullPath(string path) {
    return !String.IsNullOrWhiteSpace(path)
        && path.IndexOfAny(System.IO.Path.GetInvalidPathChars().ToArray()) == -1
        && Path.IsPathRooted(path)
        && !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal);
}

EDYCJA: EM0 zrobił dobry komentarz i alternatywną odpowiedź, odnosząc się do ciekawego przypadku ścieżek takich jak C:i C:dir. Aby pomóc zdecydować, w jaki sposób chcesz obsłużyć takie ścieżki, możesz zagłębić się w MSDN -> Aplikacje klasyczne Windows -> Programowanie -> Technologie komputerowe -> Dostęp do danych i przechowywanie -> Lokalne systemy plików - -> Zarządzanie plikami -> Informacje o zarządzaniu plikami -> Tworzenie, usuwanie i konserwacja plików -> Nazywanie plików, ścieżek i przestrzeni nazw -> W pełni kwalifikowane a względne ścieżki

W przypadku funkcji interfejsu API systemu Windows, które manipulują plikami, nazwy plików mogą często odnosić się do bieżącego katalogu, podczas gdy niektóre interfejsy API wymagają w pełni kwalifikowanej ścieżki. Nazwa pliku jest określana względem bieżącego katalogu, jeśli nie zaczyna się od jednego z następujących elementów:

  • Nazwa UNC dowolnego formatu, która zawsze zaczyna się od dwóch znaków ukośnika odwrotnego („\”). Więcej informacji można znaleźć w następnej sekcji.
  • Oznaczenie dysku z ukośnikiem odwrotnym, na przykład „C: \” lub „d: \”.
  • Pojedynczy ukośnik odwrotny, na przykład „\ katalog” lub „\ plik.txt”. Nazywa się to również ścieżką absolutną.

Jeśli nazwa pliku zaczyna się od samego oznaczenia dysku, ale nie od ukośnika odwrotnego po dwukropku, jest interpretowana jako ścieżka względna do bieżącego katalogu na dysku z określoną literą. Zwróć uwagę, że katalog bieżący może być katalogiem głównym lub nie, w zależności od tego, na co został ustawiony podczas ostatniej operacji „zmiany katalogu” na tym dysku. Przykłady tego formatu są następujące:

  • „C: tmp.txt” odnosi się do pliku o nazwie „tmp.txt” w bieżącym katalogu na dysku C.
  • „C: tempdir \ tmp.txt” odnosi się do pliku w podkatalogu do bieżącego katalogu na dysku C.

[…]

jaz
źródło
3
Podoba mi się, że to nie zgłasza nieprawidłowych ścieżek, ale zwraca prawdę dla ścieżek takich jak „C:” i „C: dir”, które są rozwiązywane przez GetFullPath przy użyciu bieżącego katalogu (więc nie są one bezwzględne). Wysłano odpowiedź, która w przypadku tych odpowiedzi zwraca fałsz.
EM0
@ EM0 - Dzięki! Właśnie czegoś mnie nauczyłeś. :)
jaz
15

Próbować

System.IO.Path.IsPathRooted(template)

Działa zarówno dla ścieżek UNC, jak i lokalnych.

Na przykład

Path.IsPathRooted(@"\\MyServer\MyShare\MyDirectory")  // returns true
Path.IsPathRooted(@"C:\\MyDirectory")  // returns true
Joe
źródło
13

Stare pytanie, ale jeszcze jedna odpowiednia odpowiedź. Jeśli chcesz upewnić się, że wolumin jest uwzględniony w ścieżce lokalnej, możesz użyć System.IO.Path.GetFullPath () w następujący sposób:

if (template == System.IO.Path.GetFullPath(template))
{
    ; //template is full path including volume or full UNC path
}
else
{
    if (useCurrentPathAndVolume)
        template = System.IO.Path.GetFullPath(template);
    else
        template = Assembly.GetExecutingAssembly().Location
}
GreggD
źródło
3
To było to, czego potrzebowałem i wydaje się bliższe pierwotnemu pytaniu, ponieważ IsPathRooted 'zwraca prawdę dla ścieżek względnych (niekoniecznie ścieżek bezwzględnych)
bitcoder
GetFullPathuzyskuje dostęp do systemu plików i może zgłosić kilka możliwych wyjątków. Zobacz moją odpowiedź ( stackoverflow.com/a/35046453/704808 ), aby znaleźć alternatywę, która nadal zapewnia pełną ścieżkę.
jaz
11

Opierając się na odpowiedzi jazu : nie powoduje to zgłaszania nieprawidłowych ścieżek, ale zwraca również falseścieżki, takie jak „C:”, „C: dirname” i „\ path”.

public static bool IsFullPath(string path)
{
    if (string.IsNullOrWhiteSpace(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1 || !Path.IsPathRooted(path))
        return false;

    string pathRoot = Path.GetPathRoot(path);
    if (pathRoot.Length <= 2 && pathRoot != "/") // Accepts X:\ and \\UNC\PATH, rejects empty string, \ and X:, but accepts / to support Linux
        return false;

    if (pathRoot[0] != '\\' || pathRoot[1] != '\\')
        return true; // Rooted and not a UNC path

    return pathRoot.Trim('\\').IndexOf('\\') != -1; // A UNC server name without a share name (e.g "\\NAME" or "\\NAME\") is invalid
}

Zwróć uwagę, że zwraca to różne wyniki w systemach Windows i Linux, np. „/ Path” jest bezwzględne w systemie Linux, ale nie w systemie Windows.

Test jednostkowy:

[Test]
public void IsFullPath()
{
    bool isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); // .NET Framework
    // bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows); // .NET Core

    // These are full paths on Windows, but not on Linux
    TryIsFullPath(@"C:\dir\file.ext", isWindows);
    TryIsFullPath(@"C:\dir\", isWindows);
    TryIsFullPath(@"C:\dir", isWindows);
    TryIsFullPath(@"C:\", isWindows);
    TryIsFullPath(@"\\unc\share\dir\file.ext", isWindows);
    TryIsFullPath(@"\\unc\share", isWindows);

    // These are full paths on Linux, but not on Windows
    TryIsFullPath(@"/some/file", !isWindows);
    TryIsFullPath(@"/dir", !isWindows);
    TryIsFullPath(@"/", !isWindows);

    // Not full paths on either Windows or Linux
    TryIsFullPath(@"file.ext", false);
    TryIsFullPath(@"dir\file.ext", false);
    TryIsFullPath(@"\dir\file.ext", false);
    TryIsFullPath(@"C:", false);
    TryIsFullPath(@"C:dir\file.ext", false);
    TryIsFullPath(@"\dir", false); // An "absolute", but not "full" path

    // Invalid on both Windows and Linux
    TryIsFullPath(null, false, false);
    TryIsFullPath("", false, false);
    TryIsFullPath("   ", false, false);
    TryIsFullPath(@"C:\inval|d", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname", false, false);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\", false, !isWindows);
    TryIsFullPath(@"\\is_this_a_dir_or_a_hostname\\", false, !isWindows);
}

private static void TryIsFullPath(string path, bool expectedIsFull, bool expectedIsValid = true)
{
    Assert.AreEqual(expectedIsFull, PathUtils.IsFullPath(path), "IsFullPath('" + path + "')");

    if (expectedIsFull)
    {
        Assert.AreEqual(path, Path.GetFullPath(path));
    }
    else if (expectedIsValid)
    {
        Assert.AreNotEqual(path, Path.GetFullPath(path));
    }
    else
    {
        Assert.That(() => Path.GetFullPath(path), Throws.Exception);
    }
}
EM0
źródło
Dobry towar. Zauważyłem, że msdn.microsoft.com/en-us/library/windows/desktop/… stwierdza, że ​​w systemie Windows ścieżka nie jest względna, jeśli zaczyna się od „Pojedynczy lewy ukośnik, na przykład„ \ katalog ”lub„ \ plik .tekst". Nazywa się to również ścieżką absolutną ”.
jaz
1
Słuszna uwaga! Wygląda na to, że moja terminologia była nieaktualna. Kiedy powiedziałem „absolutna ścieżka”, naprawdę myślałem o tym, co SM nazywa „pełną ścieżką”. Zmieniłem nazwę i dodałem do tego przypadek testowy.
EM0
1
Dzięki za tę odpowiedź, bardzo mi pomogła. Należy jednak pamiętać, że w przypadku ścieżki UNC, takiej jak \\ server \, metoda zwraca wartość true, ale spowoduje to zgłoszenie wyjątku, jeśli następnie wywołasz Directory.Exists (path) (System.ArgumentException: `` Ścieżka UNC powinna mieć postać \\ server \ share. ')
Carl
2
Miło widzieć, że ludzie nadal używają tego i znajdują nowe przypadki skrajne @Carl Zaktualizował kod i przetestował to!
EM0
6

Aby sprawdzić, czy ścieżka jest w pełni kwalifikowana (MSDN) :

public static bool IsPathFullyQualified(string path)
{
    var root = Path.GetPathRoot(path);
    return root.StartsWith(@"\\") || root.EndsWith(@"\");
}

Jest to nieco prostsze niż to, co zostało już zaproponowane, i nadal zwraca wartość false dla ścieżek względem dysku, takich jak C:foo. Jego logika jest oparta bezpośrednio na definicji „w pełni kwalifikowanej” w MSDN i nie znalazłem żadnych przykładów, na których źle się zachowuje.


Co ciekawe, wydaje się, że .NET Core 2.1 ma nową metodę, Path.IsPathFullyQualifiedktóra wykorzystuje metodę wewnętrzną PathInternal.IsPartiallyQualified(lokalizacja linków jest dokładna na 17.04.2018).

Dla potomności i lepszego samowystarczalności tego posta, oto implementacja tego ostatniego w celach informacyjnych:

internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
{
    if (path.Length < 2)
    {
        // It isn't fixed, it must be relative.  There is no way to specify a fixed
        // path with one character (or less).
        return true;
    }

    if (IsDirectorySeparator(path[0]))
    {
        // There is no valid way to specify a relative path with two initial slashes or
        // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\
        return !(path[1] == '?' || IsDirectorySeparator(path[1]));
    }

    // The only way to specify a fixed path that doesn't begin with two slashes
    // is the drive, colon, slash format- i.e. C:\
    return !((path.Length >= 3)
        && (path[1] == VolumeSeparatorChar)
        && IsDirectorySeparator(path[2])
        // To match old behavior we'll check the drive character for validity as the path is technically
        // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream.
        && IsValidDriveChar(path[0]));
}
William
źródło
4

To jest rozwiązanie, którego używam

public static bool IsFullPath(string path)
{
    try
    {
        return Path.GetFullPath(path) == path;
    }
    catch
    {
        return false;
    }
}

Działa to w następujący sposób:

IsFullPath(@"c:\foo"); // true
IsFullPath(@"C:\foo"); // true
IsFullPath(@"c:\foo\"); // true
IsFullPath(@"c:/foo"); // false
IsFullPath(@"\foo"); // false
IsFullPath(@"foo"); // false
IsFullPath(@"c:1\foo\"); // false
Mychajło Seniutowicz
źródło
Bardzo interesujące! Na przykład jest delikatny, musi pasować do typów ukośników, ale to obiecuje.
Nicholas Petersen
Zwraca błędne wyniki dla następujących ścieżek: C:\foo\..\foolubC:\foo\.\.\.
sergtk
1

Wywołaj następującą funkcję:

Path.IsPathFullyQualified(@"c:\foo")

Dokument MSDN: Metoda Path.IsPathFullyQualified

Oto przydatny cytat z dokumentu MSDN:

Ta metoda obsługuje ścieżki, które używają alternatywnego separatora katalogu. Częstym błędem jest zakładanie, że zakorzenione ścieżki ( IsPathRooted (String) ) nie są względne. Na przykład „C: a” jest względnym dyskiem, to znaczy jest rozpoznawany względem bieżącego katalogu dla C: (zakorzeniony, ale względny). „C: \ a” jest zakorzenione i nie jest względne, to znaczy bieżący katalog nie jest używany do modyfikowania ścieżki.

sergtk
źródło
0

Nie jestem do końca pewien, co masz na myśli przez pełną ścieżkę (chociaż zakładając z przykładu, że masz na myśli nie względną od korzenia), możesz użyć klasy Path, aby pomóc ci w pracy ze ścieżkami fizycznego systemu plików, które powinny obejmować w większości przypadków.

Grant Thomas
źródło