Kiểm tra xem đã cung cấp đường dẫn đầy đủ chưa


104

Có phương pháp nào để kiểm tra xem đường dẫn đã cho có phải là đường dẫn đầy đủ không? Ngay bây giờ tôi đang làm điều này:

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

Nhưng phải có cách thanh lịch hơn để kiểm tra điều này?

Câu trả lời:


141

Hãy thử sử dụng System.IO.Path.IsPathRooted? Nó cũng trả về truecho các đường dẫn tuyệt đối.

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
Tại sao ví dụ thứ hai lại là đường dẫn tuyệt đối?
om471987

3
Con đường thứ hai không phải là tuyệt đối, tuy nhiên nó được root. Dấu gạch chéo ở đầu cho biết gốc của hệ thống.
detaylor

3
@SmirkinGherkin vậy sự khác biệt giữa đường dẫn gốc và đường dẫn tuyệt đối là gì?
Jason Axelson

1
Xem câu trả lời của tôi ( stackoverflow.com/a/35046453/704808 ) để biết giải pháp thay thế đảm bảo đường dẫn đầy đủ trong khi vẫn giữ được các ưu điểm IsPathRooted: tránh truy cập vào hệ thống tệp hoặc ném ngoại lệ cho đầu vào không hợp lệ.
đập

1
@daniel, IIRC nó được bao gồm để cho thấy rằng đường dẫn không cần phải là một đường dẫn hợp lệ để được sử dụng IsPathRooted, nó chắc chắn không có gì đáng kể. Các GetFullPathdòng đã được bao gồm để các con đường đang được đánh giá có thể được quan sát
detaylor

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

Điều kiện trên:

  • không yêu cầu quyền đối với hệ thống tệp
  • trả về falsetrong hầu hết các trường hợp khi định dạng của pathkhông hợp lệ (thay vì đưa ra một ngoại lệ)
  • truechỉ trả lại nếu pathbao gồm khối lượng

Trong các tình huống như OP đã đặt ra, do đó nó có thể phù hợp hơn các điều kiện trong các câu trả lời trước đó. Không giống như điều kiện trên:

  • path == System.IO.Path.GetFullPath(path)ném các ngoại lệ thay vì trả lại falsetrong các trường hợp sau:
    • Người gọi không có các quyền cần thiết
    • Hệ thống không thể truy xuất đường dẫn tuyệt đối
    • đường dẫn chứa dấu hai chấm (":") không phải là một phần của mã định danh tập
    • Đường dẫn, tên tệp được chỉ định hoặc cả hai đều vượt quá độ dài tối đa do hệ thống xác định
  • System.IO.Path.IsPathRooted(path)trả về truenếu pathbắt đầu bằng một dấu phân tách thư mục.

Cuối cùng, đây là một phương pháp kết thúc điều kiện trên và cũng bao gồm các ngoại lệ có thể còn lại:

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

CHỈNH SỬA: EM0 đã đưa ra một nhận xét tốt và câu trả lời thay thế giải quyết trường hợp tò mò về các đường dẫn như C:C:dir. Để giúp quyết định cách bạn có thể muốn xử lý các đường dẫn như vậy, bạn có thể muốn đi sâu vào MSDN -> Ứng dụng máy tính để bàn Windows -> Phát triển -> Công nghệ máy tính để bàn -> Truy cập và lưu trữ dữ liệu -> Hệ thống tệp cục bộ - -> Quản lý tệp -> Giới thiệu về Quản lý tệp -> Tạo, xóa và duy trì tệp -> Đặt tên tệp, đường dẫn và không gian tên -> Đủ điều kiện so với Đường dẫn tương đối

Đối với các hàm API Windows thao tác tệp, tên tệp thường có thể liên quan đến thư mục hiện tại, trong khi một số API yêu cầu một đường dẫn đủ điều kiện. Tên tệp có liên quan đến thư mục hiện tại nếu nó không bắt đầu bằng một trong những điều sau:

  • Tên UNC của bất kỳ định dạng nào, luôn bắt đầu bằng hai ký tự gạch chéo ngược ("\"). Để biết thêm thông tin, hãy xem phần tiếp theo.
  • Bộ chỉ định đĩa có dấu gạch chéo ngược, ví dụ "C: \" hoặc "d: \".
  • Một dấu gạch chéo ngược, ví dụ: "\ directory" hoặc "\ file.txt". Đây cũng được coi là một đường dẫn tuyệt đối.

Nếu tên tệp chỉ bắt đầu bằng bộ chỉ định đĩa mà không phải dấu gạch chéo ngược sau dấu hai chấm, thì nó được hiểu là một đường dẫn tương đối đến thư mục hiện tại trên ổ đĩa với ký tự được chỉ định. Lưu ý rằng thư mục hiện tại có thể là thư mục gốc hoặc có thể không phải là thư mục gốc tùy thuộc vào những gì nó được đặt thành trong hoạt động "thay đổi thư mục" gần đây nhất trên đĩa đó. Ví dụ về định dạng này như sau:

  • "C: tmp.txt" đề cập đến một tệp có tên "tmp.txt" trong thư mục hiện tại trên ổ C.
  • "C: tempdir \ tmp.txt" đề cập đến một tệp trong thư mục con của thư mục hiện tại trên ổ C.

[...]


3
Tôi thích rằng điều này không ném cho các đường dẫn không hợp lệ, nhưng nó trả về true cho các đường dẫn như "C:" và "C: dir", được GetFullPath giải quyết bằng cách sử dụng thư mục hiện tại (vì vậy chúng không phải là tuyệt đối). Đã đăng một câu trả lời trả về sai cho những điều này.
EM0

@ EM0 - Cảm ơn! Bạn chỉ dạy cho tôi một cái gì đó. :)
weir

15

Thử

System.IO.Path.IsPathRooted(template)

Hoạt động cho các đường dẫn UNC cũng như các đường dẫn cục bộ.

Ví dụ

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

13

Câu hỏi cũ, nhưng một câu trả lời áp dụng hơn. Nếu bạn cần đảm bảo ổ đĩa được bao gồm trong một đường dẫn cục bộ, bạn có thể sử dụng System.IO.Path.GetFullPath () như sau:

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
Đây là những gì tôi cần và có vẻ gần với câu hỏi ban đầu hơn vì IsPathRooted 'trả về true cho các đường dẫn tương đối (không nhất thiết phải là đường dẫn tuyệt đối)
bitcoder

GetFullPathtruy cập vào hệ thống tệp và có thể đưa ra một số ngoại lệ có thể xảy ra. Xem câu trả lời của tôi ( stackoverflow.com/a/35046453/704808 ) để biết giải pháp thay thế vẫn đảm bảo đường dẫn đầy đủ.
đập

11

Dựa trên câu trả lời của weir : điều này không ném cho các đường dẫn không hợp lệ mà còn trả về falsecho các đường dẫn như "C:", "C: dirname" và "\ 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
}

Lưu ý rằng điều này trả về các kết quả khác nhau trên Windows và Linux, ví dụ: "/ path" là tuyệt đối trên Linux, nhưng không phải trên Windows.

Bài kiểm tra đơn vị:

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

Đồ tốt. Tôi nhận thấy rằng msdn.microsoft.com/en-us/library/windows/desktop/… tuyên bố rằng trên Windows, một đường dẫn không phải là tương đối nếu nó bắt đầu bằng 'Một dấu gạch chéo ngược, ví dụ: "\ directory" hoặc "\ file .txt ”. Đây cũng được coi là một đường dẫn tuyệt đối. '
weir

1
Điểm tốt! Có vẻ như thuật ngữ của tôi đã bị tắt. Khi tôi nói "đường dẫn tuyệt đối", tôi thực sự đang nghĩ đến cái mà MS gọi là "đường dẫn đầy đủ". Tôi đã đổi tên và thêm một trường hợp thử nghiệm cho điều này.
EM0

1
Cảm ơn vì câu trả lời này, nó đã giúp tôi rất nhiều. Tuy nhiên, lưu ý rằng đối với một đường dẫn UNC chẳng hạn như \\ server \, phương thức trả về true, nhưng điều này sẽ ném ra một ngoại lệ nếu sau đó bạn gọi Directory.Exists (path) (System.ArgumentException: 'Đường dẫn UNC phải có dạng \\ server \ share. ')
Carl

2
Rất vui khi thấy mọi người vẫn sử dụng cái này và tìm ra các trường hợp cạnh mới @Carl Đã cập nhật mã và thử nghiệm cho điều đó!
EM0

6

Để kiểm tra xem một đường dẫn có đủ điều kiện hay không (MSDN) :

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

Nó đơn giản hơn một chút so với những gì đã được đề xuất và nó vẫn trả về false cho các đường dẫn liên quan đến ổ đĩa như C:foo. Logic của nó dựa trực tiếp vào định nghĩa "đủ điều kiện" của MSDN và tôi không tìm thấy bất kỳ ví dụ nào mà nó hoạt động sai.


Tuy nhiên, điều thú vị là .NET Core 2.1 dường như có một phương pháp mới Path.IsPathFullyQualifiedsử dụng một phương thức nội bộPathInternal.IsPartiallyQualified (vị trí liên kết chính xác kể từ 2018-04-17).

Đối với hậu thế và tự ngăn chặn bài đăng này tốt hơn, đây là cách triển khai sau này để tham khảo:

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

Đây là giải pháp tôi sử dụng

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

Nó hoạt động theo cách sau:

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

Rất thú vị! Ví dụ, nó mỏng manh, phải phù hợp với các loại gạch chéo, nhưng điều này có hứa hẹn.
Nicholas Petersen

Nó sẽ trả về kết quả sai cho các đường dẫn sau: C:\foo\..\foohoặcC:\foo\.\.\.
sergtk

1

Gọi hàm sau:

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

Tài liệu MSDN: Phương thức Path.IsPathFullyQualified

Trích dẫn hữu ích từ tài liệu MSDN như sau:

Phương pháp này xử lý các đường dẫn sử dụng dấu phân tách thư mục thay thế. Một sai lầm thường gặp khi cho rằng các đường dẫn gốc ( IsPathRooted (String) ) không tương đối. Ví dụ: "C: a" là ổ đĩa tương đối, nghĩa là, nó được phân giải dựa trên thư mục hiện tại cho C: (root, nhưng là tương đối). "C: \ a" được root và không phải là tương đối, nghĩa là thư mục hiện tại không được sử dụng để sửa đổi đường dẫn.


0

Tôi không thực sự chắc chắn ý của bạn về đường dẫn đầy đủ (mặc dù giả sử từ ví dụ, bạn có nghĩa là không tương đối từ gốc trở đi), bạn có thể sử dụng lớp Path để hỗ trợ bạn làm việc với các đường dẫn hệ thống tệp vật lý. bạn cho hầu hết các trường hợp cuối cùng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.