ตรวจสอบว่าให้เส้นทางแบบเต็มหรือไม่


105

มีวิธีตรวจสอบว่าเส้นทางที่กำหนดเป็นเส้นทางเต็มหรือไม่? ตอนนี้ฉันกำลังทำสิ่งนี้:

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

แต่ต้องมีวิธีที่หรูหรากว่านี้สำหรับการตรวจสอบสิ่งนี้หรือไม่?

คำตอบ:


142

ลองใช้System.IO.Path.IsPathRootedไหม? นอกจากนี้ยังส่งกลับtrueสำหรับเส้นทางที่แน่นอน

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"

14
ตัวอย่างที่สองเป็นเส้นทางที่แน่นอนได้อย่างไร?
om471987

4
เส้นทางที่สองไม่แน่นอนอย่างไรก็ตามมีการรูท เครื่องหมายทับนำหน้าบ่งบอกถึงรากของระบบ
detaylor

3
@SmirkinGherkin ดังนั้นความแตกต่างระหว่างเส้นทางที่รูทและสัมบูรณ์คืออะไร?
Jason Axelson

1
ดูคำตอบของฉัน ( stackoverflow.com/a/35046453/704808 ) สำหรับทางเลือกอื่นที่ทำให้แน่ใจว่าเส้นทางเต็มในขณะที่ยังคงรักษาข้อดีของIsPathRooted: หลีกเลี่ยงการเข้าถึงระบบไฟล์หรือโยนข้อยกเว้นสำหรับอินพุตที่ไม่ถูกต้อง
ฝาย

1
@daniel, IIRC ถูกรวมไว้เพื่อแสดงให้เห็นว่าเส้นทางนั้นไม่จำเป็นต้องเป็นเส้นทางที่ถูกต้องที่จะใช้กับIsPathRootedมันไม่ได้มีนัยสำคัญอะไร รวมGetFullPathสายเพื่อให้สามารถสังเกตเส้นทางที่กำลังประเมินได้
detaylor

30
Path.IsPathRooted(path)
&& !Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)

เงื่อนไขข้างต้น:

  • ไม่ต้องการสิทธิ์ระบบไฟล์
  • ส่งคืนfalseในกรณีส่วนใหญ่ที่รูปแบบของpathไม่ถูกต้อง (แทนที่จะโยนข้อยกเว้น)
  • ส่งคืนtrueเฉพาะในกรณีที่pathมีไดรฟ์ข้อมูล

ในสถานการณ์เช่นเดียวกับที่ OP วางไว้ดังนั้นจึงอาจเหมาะสมกว่าเงื่อนไขในคำตอบก่อนหน้านี้ ไม่เหมือนกับเงื่อนไขข้างต้น:

  • path == System.IO.Path.GetFullPath(path)โยนข้อยกเว้นแทนที่จะส่งคืนfalseในสถานการณ์เหล่านี้:
    • ผู้โทรไม่มีสิทธิ์ที่จำเป็น
    • ระบบไม่สามารถดึงเส้นทางสัมบูรณ์ได้
    • เส้นทางมีเครื่องหมายจุดคู่ (":") ที่ไม่ได้เป็นส่วนหนึ่งของตัวระบุโวลุ่ม
    • พา ธ ที่ระบุชื่อไฟล์หรือทั้งสองอย่างเกินความยาวสูงสุดที่ระบบกำหนด
  • System.IO.Path.IsPathRooted(path)ส่งคืนtrueหากpathขึ้นต้นด้วยตัวคั่นไดเร็กทอรีเดียว

ในที่สุดนี่คือวิธีการที่ครอบคลุมเงื่อนไขข้างต้นและยึดข้อยกเว้นที่เป็นไปได้ที่เหลืออยู่:

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

แก้ไข: EM0 ได้แสดงความคิดเห็นที่ดีและคำตอบทางเลือกที่อยู่กรณีที่อยากรู้อยากเห็นของเส้นทางเหมือนและC: C:dirเพื่อช่วยในการตัดสินใจว่าคุณต้องการจัดการเส้นทางดังกล่าวอย่างไรคุณอาจต้องการดำน้ำลึกไปที่ MSDN -> แอปพลิเคชันเดสก์ท็อป Windows -> พัฒนา -> เทคโนโลยีเดสก์ท็อป -> การเข้าถึงข้อมูลและการจัดเก็บ -> ระบบไฟล์ในเครื่อง - -> การจัดการไฟล์ -> เกี่ยวกับการจัดการไฟล์ -> การสร้างการลบและการดูแลรักษาไฟล์ -> การตั้งชื่อไฟล์เส้นทางและเนมสเปซ -> ผ่านการรับรองอย่างสมบูรณ์เทียบกับพา ธ สัมพัทธ์

สำหรับฟังก์ชัน Windows API ที่จัดการไฟล์ชื่อไฟล์มักจะสัมพันธ์กับไดเร็กทอรีปัจจุบันในขณะที่ API บางตัวต้องการพา ธ แบบเต็ม ชื่อไฟล์จะสัมพันธ์กับไดเร็กทอรีปัจจุบันหากไม่ได้ขึ้นต้นด้วยอย่างใดอย่างหนึ่งต่อไปนี้:

  • ชื่อ UNC ของรูปแบบใดก็ได้ซึ่งจะขึ้นต้นด้วยอักขระแบ็กสแลชสองตัว ("\") เสมอ สำหรับข้อมูลเพิ่มเติมโปรดดูหัวข้อถัดไป
  • ตัวกำหนดดิสก์ที่มีเครื่องหมายแบ็กสแลชตัวอย่างเช่น "C: \" หรือ "d: \"
  • แบ็กสแลชเดียวตัวอย่างเช่น "\ directory" หรือ "\ file.txt" สิ่งนี้เรียกอีกอย่างว่าเส้นทางสัมบูรณ์

หากชื่อไฟล์ขึ้นต้นด้วยตัวออกแบบดิสก์เท่านั้น แต่ไม่ใช่เครื่องหมายแบ็กสแลชหลังเครื่องหมายจุดคู่จะถูกตีความว่าเป็นพา ธ สัมพัทธ์ไปยังไดเร็กทอรีปัจจุบันบนไดรฟ์ด้วยตัวอักษรที่ระบุ โปรดสังเกตว่าไดเร็กทอรีปัจจุบันอาจเป็นหรือไม่ใช่ไดเร็กทอรีรูทขึ้นอยู่กับสิ่งที่ถูกตั้งค่าในระหว่างการดำเนินการ "เปลี่ยนไดเร็กทอรี" ล่าสุดบนดิสก์นั้น ตัวอย่างของรูปแบบนี้มีดังนี้:

  • "C: tmp.txt" หมายถึงไฟล์ชื่อ "tmp.txt" ในไดเร็กทอรีปัจจุบันบนไดรฟ์ C
  • "C: tempdir \ tmp.txt" หมายถึงไฟล์ในไดเร็กทอรีย่อยไปยังไดเร็กทอรีปัจจุบันบนไดรฟ์ C

[... ]


3
ฉันชอบที่สิ่งนี้ไม่ได้ทำให้เกิดเส้นทางที่ไม่ถูกต้อง แต่จะคืนค่าจริงสำหรับเส้นทางเช่น "C:" และ "C: dir" ซึ่ง GetFullPath แก้ไขโดยใช้ไดเรกทอรีปัจจุบัน (ดังนั้นจึงไม่สมบูรณ์) โพสต์คำตอบที่ส่งคืนเท็จสำหรับสิ่งเหล่านี้
EM0

@ EM0 - ขอบคุณ! คุณเพิ่งสอนฉันบางอย่าง :)
ฝาย

15

ลอง

System.IO.Path.IsPathRooted(template)

ใช้ได้กับเส้นทาง UNC เช่นเดียวกับเส้นทางท้องถิ่น

เช่น

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

13

คำถามเก่า แต่มีอีกหนึ่งคำตอบที่ใช้ได้ หากคุณต้องการให้แน่ใจว่าไดรฟ์ข้อมูลรวมอยู่ในโลคัลพา ธ คุณสามารถใช้ System.IO.Path.GetFullPath () ดังนี้:

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
}

3
นี่คือสิ่งที่ฉันต้องการและดูเหมือนจะใกล้เคียงกับคำถามเดิมมากขึ้นเนื่องจาก IsPathRooted 'ส่งคืนจริงสำหรับเส้นทางสัมพัทธ์ (ไม่จำเป็นต้องเป็นเส้นทางที่แน่นอน)
bitcoder

GetFullPathเข้าถึงระบบไฟล์และสามารถทิ้งข้อยกเว้นที่เป็นไปได้จำนวนมาก ดูคำตอบของฉัน ( stackoverflow.com/a/35046453/704808 ) สำหรับทางเลือกอื่นที่ยังคงให้แน่ใจว่าเส้นทางเต็ม
ฝาย

11

การสร้างคำตอบของฝาย : สิ่งนี้ไม่ได้ส่งผลให้เส้นทางที่ไม่ถูกต้อง แต่ยังส่งกลับfalseสำหรับเส้นทางเช่น "C:", "C: dirname" และ "\ 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
}

โปรดทราบว่าสิ่งนี้จะส่งคืนผลลัพธ์ที่แตกต่างกันใน Windows และ Linux เช่น "/ path" เป็นแบบสัมบูรณ์บน Linux แต่ไม่ใช่บน Windows

การทดสอบหน่วย:

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

สิ่งที่ดี. ฉันสังเกตเห็นว่าmsdn.microsoft.com/en-us/library/windows/desktop/…ระบุว่าบน Windows เส้นทางไม่สัมพันธ์กันหากขึ้นต้นด้วย'เครื่องหมายแบ็กสแลชเดียวตัวอย่างเช่น "\ directory" หรือ "\ file .txt ". สิ่งนี้เรียกอีกอย่างว่าเส้นทางสัมบูรณ์ '
ฝาย

1
จุดดี! ดูเหมือนว่าศัพท์ของฉันถูกปิด เมื่อฉันพูดว่า "เส้นทางสัมบูรณ์" ฉันคิดถึงสิ่งที่ MS เรียกว่า "เส้นทางเต็ม" จริงๆ ฉันได้เปลี่ยนชื่อและเพิ่มกรณีทดสอบสำหรับสิ่งนี้
EM0

1
ขอบคุณสำหรับคำตอบนี้มันช่วยฉันได้มาก อย่างไรก็ตามโปรดทราบว่าสำหรับเส้นทาง UNC เช่น \\ server \ วิธีนี้จะคืนค่าจริง แต่จะทำให้เกิดข้อยกเว้นหากคุณเรียก Directory.Exists (เส้นทาง) (System.ArgumentException: 'เส้นทาง UNC ควรอยู่ในรูปแบบ \\ server \ share. ')
Carl

2
ยินดีที่ได้เห็นผู้คนยังคงใช้สิ่งนี้และพบกับเคสใหม่ล่าสุด @Carl อัปเดตโค้ดและทดสอบสิ่งนั้น!
EM0

7

วิธีตรวจสอบว่าพา ธ มีคุณสมบัติครบถ้วนหรือไม่ (MSDN) :

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

มันง่ายกว่าที่เสนอไปแล้วเล็กน้อยและยังคงส่งคืนเท็จสำหรับพา ธ สัมพัทธ์ของไดรฟ์เช่นC:foo. ตรรกะของมันเป็นไปตามนิยาม MSDN ของ "คุณสมบัติครบถ้วน" โดยตรงและฉันไม่พบตัวอย่างใด ๆ ที่มันทำงานผิดปกติ


อย่างไรก็ตามที่น่าสนใจคือ. NET Core 2.1 ดูเหมือนจะมีวิธีการใหม่Path.IsPathFullyQualifiedที่ใช้วิธีการภายในPathInternal.IsPartiallyQualified(ตำแหน่งลิงค์ถูกต้อง ณ วันที่ 2018-04-17)

สำหรับลูกหลานและการควบคุมตนเองที่ดีขึ้นของโพสต์นี้ต่อไปนี้เป็นการนำไปใช้เพื่อการอ้างอิง:

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

4

นี่คือวิธีแก้ปัญหาที่ฉันใช้

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

ทำงานด้วยวิธีต่อไปนี้:

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

น่าสนใจมาก! ตัวอย่างเช่นมันบอบบางต้องจับคู่ประเภทสแลช แต่สิ่งนี้มีสัญญา
Nicholas Petersen

ส่งคืนผลลัพธ์ที่ไม่ถูกต้องสำหรับเส้นทางต่อไปนี้: C:\foo\..\fooหรือC:\foo\.\.\.
sergtk

1

เรียกใช้ฟังก์ชันต่อไปนี้:

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

MSDN doc: Path.IsPathFullyQualified Method

การอ้างอิงที่เป็นประโยชน์จาก MSDN doc มีดังนี้:

วิธีนี้จัดการกับพา ธ ที่ใช้ตัวคั่นไดเร็กทอรีสำรอง เป็นความผิดพลาดบ่อยครั้งที่จะถือว่าพา ธ ที่รูท ( IsPathRooted (String) ) ไม่สัมพันธ์กัน ตัวอย่างเช่น "C: a" เป็นญาติของไดรฟ์นั่นคือได้รับการแก้ไขกับไดเร็กทอรีปัจจุบันสำหรับ C: (รูท แต่สัมพันธ์กัน) "C: \ a" ถูกรูทและไม่สัมพันธ์กันนั่นคือไม่ได้ใช้ไดเร็กทอรีปัจจุบันเพื่อแก้ไขเส้นทาง


0

ฉันไม่แน่ใจจริงๆว่าคุณหมายถึงอะไรตามเส้นทางแบบเต็ม (แม้ว่าจะสมมติว่าจากตัวอย่างคุณหมายถึงไม่สัมพันธ์กันตั้งแต่รูทเป็นต้นไป) คุณสามารถใช้คลาสPathเพื่อช่วยคุณในการทำงานกับพา ธระบบไฟล์ฟิสิคัลซึ่งควรครอบคลุม คุณสำหรับเหตุการณ์ส่วนใหญ่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.