Periksa apakah jalur lengkap diberikan

104

Apakah ada metode untuk memeriksa apakah jalur yang diberikan adalah jalur lengkap? Sekarang saya melakukan ini:

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

Tapi pasti ada cara yang lebih elegan untuk memeriksa ini?

hs2d
sumber

Jawaban:

141

Coba gunakan System.IO.Path.IsPathRooted? Itu juga kembali trueuntuk jalur absolut.

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.dll
sumber
14
Kenapa contoh kedua menjadi jalur absolut?
om471987
4
Jalan kedua tidak mutlak, namun telah di-root. Garis miring di depan menunjukkan root dari sistem.
detaylor
3
@SmirkinGherkin jadi apa perbedaan antara jalur yang di-root dan absolut?
Jason Axelson
1
Lihat jawaban saya ( stackoverflow.com/a/35046453/704808 ) untuk alternatif yang memastikan jalur lengkap sambil tetap mempertahankan keuntungan dari IsPathRooted: menghindari mengakses sistem file atau memberikan pengecualian untuk input yang tidak valid.
bendung
1
@daniel, IIRC itu disertakan untuk menunjukkan bahwa jalur tidak perlu menjadi jalur yang valid untuk digunakan IsPathRooted, tentu saja tidak ada yang signifikan. The GetFullPathgaris termasuk sehingga jalan sedang dievaluasi dapat diamati
detaylor
30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

Kondisi diatas:

  • tidak memerlukan izin sistem file
  • mengembalikan falsedalam banyak kasus di mana format pathtidak valid (daripada melempar pengecualian)
  • kembali truehanya jika pathmenyertakan volume

Dalam skenario seperti yang diajukan OP, oleh karena itu mungkin lebih cocok daripada kondisi pada jawaban sebelumnya. Berbeda dengan kondisi diatas:

  • path == System.IO.Path.GetFullPath(path)melempar pengecualian daripada kembali falsedalam skenario ini:
    • Penelepon tidak memiliki izin yang diperlukan
    • Sistem tidak dapat mengambil jalur absolut
    • path berisi titik dua (":") yang bukan merupakan bagian dari pengenal volume
    • Jalur yang ditentukan, nama file, atau keduanya melebihi panjang maksimum yang ditentukan sistem
  • System.IO.Path.IsPathRooted(path)kembali truejika pathdimulai dengan pemisah direktori tunggal.

Terakhir, berikut adalah metode yang membungkus kondisi di atas dan juga menutup kemungkinan pengecualian yang tersisa:

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

EDIT: EM0 membuat komentar yang bagus dan jawaban alternatif yang menangani kasus aneh jalur seperti C:dan C:dir. Untuk membantu memutuskan bagaimana Anda mungkin ingin menangani jalur tersebut, Anda mungkin ingin mempelajari MSDN -> aplikasi desktop Windows -> Kembangkan -> Teknologi desktop -> Akses dan Penyimpanan Data -> Sistem File Lokal - -> Manajemen File -> Tentang Manajemen File -> Membuat, Menghapus, dan Memelihara File -> Menamai File, Jalur, dan Namespaces -> Jalur Berkualifikasi Penuh vs. Relatif

Untuk fungsi Windows API yang memanipulasi file, nama file sering kali dapat dikaitkan dengan direktori saat ini, sementara beberapa API memerlukan jalur yang sepenuhnya memenuhi syarat. Nama file bersifat relatif terhadap direktori saat ini jika tidak dimulai dengan salah satu dari berikut ini:

  • Nama UNC dalam format apa pun, yang selalu dimulai dengan dua karakter garis miring terbalik ("\"). Untuk informasi lebih lanjut, lihat bagian selanjutnya.
  • Penunjuk disk dengan garis miring terbalik, misalnya "C: \" atau "d: \".
  • Satu garis miring terbalik, misalnya, "\ direktori" atau "\ file.txt". Ini juga disebut sebagai jalur absolut.

Jika nama file dimulai dengan hanya penunjuk disk tetapi tidak dengan garis miring terbalik setelah titik dua, itu diartikan sebagai jalur relatif ke direktori saat ini pada drive dengan huruf yang ditentukan. Perhatikan bahwa direktori saat ini mungkin atau mungkin bukan direktori root tergantung pada apa yang disetel selama operasi "direktori perubahan" terbaru pada disk tersebut. Contoh format ini adalah sebagai berikut:

  • "C: tmp.txt" mengacu pada file bernama "tmp.txt" di direktori saat ini di drive C.
  • "C: tempdir \ tmp.txt" merujuk ke file di subdirektori ke direktori saat ini di drive C.

[...]

bendung
sumber
3
Saya suka bahwa ini tidak menampilkan jalur yang tidak valid, tetapi mengembalikan nilai true untuk jalur seperti "C:" dan "C: dir", yang diselesaikan oleh GetFullPath menggunakan direktori saat ini (jadi tidak mutlak). Memposting jawaban yang mengembalikan false untuk ini.
EM0
@ EM0 - Terima kasih! Anda baru saja mengajari saya sesuatu. :)
bendung
15

Mencoba

System.IO.Path.IsPathRooted(template)

Bekerja untuk jalur UNC serta jalur lokal.

Misalnya

Path.IsPathRooted(@"\\MyServer\MyShare\MyDirectory")  // returns true
Path.IsPathRooted(@"C:\\MyDirectory")  // returns true
Joe
sumber
13

Pertanyaan lama, tapi satu jawaban lagi yang bisa diterapkan. Jika Anda perlu memastikan volume disertakan dalam jalur lokal, Anda dapat menggunakan System.IO.Path.GetFullPath () seperti ini:

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
sumber
3
Inilah yang saya butuhkan, dan tampaknya lebih dekat dengan pertanyaan asli karena IsPathRooted 'mengembalikan true untuk jalur relatif (tidak harus jalur absolut)
bitcoder
GetFullPathmengakses sistem file dan dapat memberikan sejumlah kemungkinan pengecualian. Lihat jawaban saya ( stackoverflow.com/a/35046453/704808 ) untuk alternatif yang masih memastikan jalur lengkap.
bendung
11

Membangun jawaban weir : ini tidak menampilkan jalur yang tidak valid, tetapi juga mengembalikan falseuntuk jalur seperti "C:", "C: dirname" dan "\ 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
}

Perhatikan bahwa ini mengembalikan hasil yang berbeda pada Windows dan Linux, misalnya "/ path" adalah absolut di Linux, tetapi tidak di Windows.

Tes unit:

[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
sumber
Barang bagus. Saya memperhatikan bahwa msdn.microsoft.com/en-us/library/windows/desktop/… menyatakan bahwa pada Windows sebuah jalur tidak relatif jika diawali dengan 'A single backslash, misalnya, "\ directory" atau "\ file .txt". Ini juga disebut sebagai jalan absolut. '
bendung
1
Poin bagus! Sepertinya terminologi saya tidak aktif. Ketika saya mengatakan "jalur absolut", saya benar-benar memikirkan apa yang disebut MS sebagai "jalur penuh". Saya telah mengubah nama dan menambahkan kasus uji untuk ini.
EM0
1
Terima kasih atas jawaban ini, ini sangat membantu saya. Namun, perhatikan bahwa untuk jalur UNC seperti \\ server \, metode ini mengembalikan nilai true, tetapi ini akan memunculkan pengecualian jika Anda kemudian memanggil Directory.Exists (jalur) (System.ArgumentException: 'Jalur UNC harus dalam bentuk \\ server \ share. ')
Carl
2
Senang melihat orang-orang masih menggunakan ini dan menemukan kasus edge baru @Carl Memperbarui kode dan mengujinya!
EM0
6

Untuk memeriksa apakah jalur sepenuhnya memenuhi syarat (MSDN) :

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

Ini sedikit lebih sederhana daripada yang telah diusulkan, dan masih mengembalikan false untuk jalur relatif-drive seperti C:foo. Logikanya didasarkan langsung pada definisi MSDN "berkualifikasi penuh", dan saya belum menemukan contoh perilaku yang tidak semestinya.


Namun yang menarik, .NET Core 2.1 tampaknya memiliki metode baru Path.IsPathFullyQualifiedyang menggunakan metode internal PathInternal.IsPartiallyQualified(lokasi tautan akurat pada 2018-04-17).

Untuk anak cucu dan penahanan diri yang lebih baik dari posting ini, inilah implementasi yang terakhir untuk referensi:

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
sumber
4

Ini adalah solusi yang saya gunakan

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

Ini bekerja dengan cara berikut:

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
Mykhailo Seniutovych
sumber
Sangat menarik! Ini rapuh, misalnya, harus cocok dengan jenis garis miring, tetapi ini menjanjikan.
Nicholas Petersen
Ini mengembalikan hasil yang salah untuk jalur berikut: C:\foo\..\fooatauC:\foo\.\.\.
sergtk
1

Panggil fungsi berikut:

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

Dok MSDN: Metode Path.IsPathFullyQualified

Kutipan berguna dari dokumen MSDN berikut:

Metode ini menangani jalur yang menggunakan pemisah direktori alternatif. Merupakan kesalahan yang sering terjadi untuk menganggap bahwa jalur yang di-root ( IsPathRooted (String) ) tidak relatif. Misalnya, "C: a" adalah drive relatif, artinya, diselesaikan terhadap direktori saat ini untuk C: (berakar, tetapi relatif). "C: \ a" di-root dan tidak relatif, artinya, direktori saat ini tidak digunakan untuk mengubah jalur.

sergtk
sumber
0

Saya tidak begitu yakin apa yang Anda maksud dengan jalur lengkap (meskipun dengan asumsi dari contoh yang Anda maksud non-relatif dari root dan seterusnya), nah, Anda dapat menggunakan kelas Path untuk membantu Anda dalam bekerja dengan jalur sistem file fisik, yang harus mencakup Anda untuk sebagian besar kemungkinan.

Berikan Thomas
sumber