Kiểm tra xem một chuỗi có phải là đường dẫn thư mục (thư mục) Windows hợp lệ không


84

Tôi đang cố gắng xác định xem liệu một chuỗi nhập bởi người dùng có hợp lệ để đại diện cho một đường dẫn đến một thư mục hay không. Hợp lệ, ý tôi là được định dạng đúng.

Trong ứng dụng của tôi, thư mục đại diện cho một điểm đến cài đặt. Với điều kiện là các đường dẫn thư mục hợp lệ, tôi muốn để xác định xem các thư mục tồn tại, và tạo ra nó nếu nó không.

Tôi hiện đang sử dụng IO.Directory.Exists( String path ). Tôi thấy rằng điều này hoạt động tốt ngoại trừ khi người dùng không định dạng chuỗi đúng cách. Khi điều đó xảy ra, phương thức này sẽ trả về false cho biết rằng thư mục không tồn tại. Nhưng đây là một vấn đề vì tôi sẽ không thể tạo thư mục sau đó.

Từ googling của mình, tôi đã tìm thấy đề xuất sử dụng biểu thức chính quy để kiểm tra xem định dạng có phù hợp hay không. Tôi không có kinh nghiệm với cụm từ thông dụng và đang tự hỏi liệu đó có phải là cách tiếp cận khả thi hay không. Đây là những gì tôi tìm thấy:

Regex r = new Regex( @"^(([a-zA-Z]\:)|(\\))(\\{1}|((\\{1})[^\\]([^/:*?<>""|]*))+)$" );
return r.IsMatch( path );

Liệu một bài kiểm tra biểu thức chính quy kết hợp với Directory.Exists(), cung cấp cho tôi một phương pháp đủ tốt để kiểm tra xem đường dẫn có hợp lệ hay không và liệu nó có tồn tại không? Tôi biết điều này sẽ thay đổi theo hệ điều hành và các yếu tố khác, nhưng chương trình chỉ được nhắm mục tiêu cho người dùng Windows .


1
Nếu nó không tạo thư mục sau khi Directory.Exists trả về false, đó không phải là một dấu hiệu khá tốt cho thấy người dùng đã cung cấp đầu vào không hợp lệ?
Robert Harvey



2
@RobertTôi đã thấy câu hỏi đó và nó không đưa ra câu trả lời cụ thể nào ngoài các quy tắc chung. Câu trả lời cao thứ 2 không bao gồm định dạng mà chỉ có các ký tự không hợp lệ. Ngoài ra, phương thức Directory.Exists có thể trả về false, nhưng vì tôi muốn tùy chọn tạo thư mục ngay tại chỗ nên tôi không thể thực hiện theo cách đó.
Pudpuduk

@Robert Ở chủ đề thứ 2 mà bạn đã liên kết - nhập một từ duy nhất sẽ vẫn vượt qua xác nhận được đưa ra trong các câu trả lời cho câu hỏi đó.
Pudpuduk

Câu trả lời:


116

Gọi điện thoại Path.GetFullPath; nó sẽ ném ra các ngoại lệ nếu đường dẫn không hợp lệ.

Để không cho phép các đường dẫn tương đối (chẳng hạn như Word), hãy gọi Path.IsPathRooted.


Tôi biết có một cái gì đó đơn giản hơn! Và cảm ơn, tôi đã không nghĩ đến vấn đề đường đi-tương-đối.
Pudpuduk

2
Cảm ơn SLaks. Tôi đã thấy nhiều bản sao và thực hiện nhiều tìm kiếm trên Google (nhiều lần), nhưng đây là lần đầu tiên tôi thấy câu trả lời tốt cho câu hỏi cụ thể này.
Robert Harvey

5
Path.GetFullPath ("con.txt") là tên tệp hợp lệ.
Christoffer

8
@Slaks Cái này đã quá cũ để để lại bình luận, nhưng tôi vẫn muốn để lại một bình luận ở đây vì lý do tôi đã cho bạn số phiếu của tôi là -1. Path.GetFullPath () có vẻ hoạt động tốt, nhưng nếu đường dẫn là: "Z: \\\\\\\\\ Hi \\\\\\\ There", nó không phải là một đường dẫn tuyệt đối hợp lệ mà là Path.GetFullPath (...) đưa ra kết quả: Z: \ Hi \ There và không có ngoại lệ nào được nêu ra. Tôi đã phải thay đổi nó một chút bằng cách so sánh chuỗi được trả về bởi GetFullPath () và chuỗi gốc như thế này: private bool IsPathValid (string path) {try {string fullPath = Path.GetFullPath (path); trả về đường dẫn fullPath ==; } catch {return false;}}
King King

4
@KingKing Từ câu trả lời Linux này trên unix.stackexchange.com: "Nhiều dấu gạch chéo được cho phép và tương đương với một dấu gạch chéo .." Tôi đã quan sát thấy điều tương tự trên Windows (mặc dù các dấu gạch chéo đầu tiên trong đường dẫn UNC có thể được xử lý khác nhau). Dùng cho chứng này, tại một Command Prompt, hãy thử này: cd C:\\\\\\\Windows\\\\\\\System32. Đối với Windows, tôi không thể tìm thấy nguồn có thẩm quyền ghi lại hành vi này, nhưng tất nhiên sẽ hoan nghênh một con trỏ đến một.
DavidRR

20

Tôi thực sự không đồng ý với SLaks. Giải pháp đó đã không làm việc cho tôi. Ngoại lệ đã không xảy ra như mong đợi. Nhưng mã này đã làm việc cho tôi:

if(System.IO.Directory.Exists(path))
{
    ...
}

62
Một đường dẫn hợp lệ không nhất thiết phải là một thư mục đó tồn tại ... đó là chính xác những vấn đề hỏi ở đây
Benlitz

1
câu hỏi có liên quan đến xác thực chuỗi đường dẫn, một đường dẫn có thể không tồn tại.
Mubashar

Tôi nghĩ cách này là đúng. Không nên mong đợi các trường hợp ngoại lệ. Phương pháp này cũng kiểm tra các ký tự không chính xác trong đường dẫn đã cho.
Eugene Maksimov

Điều kiện này tự nó sẽ ném ra một ngoại lệ nếu "đường dẫn" được tìm thấy không phải là một đường dẫn thực vì Directory.Exists yêu cầu một đường dẫn hợp lệ.
M. Fawad Surosh

Câu trả lời sai hoàn toàn! Tôi tự hỏi làm thế nào nó nhận được 32 phiếu bầu (tính đến thời điểm hiện tại). Chắc hẳn là bởi những người đã nhìn sai chỗ cho vấn đề họ đang gặp phải, và họ đã vấp phải điều này.
Sнаđошƒаӽ

13

Path.GetFullPath chỉ đưa ra các ngoại lệ dưới đây

Đường dẫn ArgumentException là một chuỗi có độ dài bằng 0, chỉ chứa khoảng trắng hoặc chứa một hoặc nhiều ký tự không hợp lệ được xác định trong GetInvalidPathChars. -hoặc- Hệ thống không thể truy xuất đường dẫn tuyệt đối.

SecurityException Người gọi không có các quyền cần thiết.

Đường dẫn ArgumentNullException là rỗng.

Đường dẫn NotSupportedException chứa dấu hai chấm (":") không phải là một phần của mã định danh khối lượng (ví dụ: "c: \").

PathTooLongException Đườ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. Ví dụ: trên nền tảng Windows, đường dẫn phải ít hơn 248 ký tự và tên tệp phải dưới 260 ký tự.

Cách thay thế là sử dụng như sau:

/// <summary>
/// Validate the Path. If path is relative append the path to the project directory by default.
/// </summary>
/// <param name="path">Path to validate</param>
/// <param name="RelativePath">Relative path</param>
/// <param name="Extension">If want to check for File Path</param>
/// <returns></returns>
private static bool ValidateDllPath(ref string path, string RelativePath = "", string Extension = "")
{
    // Check if it contains any Invalid Characters.
    if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1)
    {
        try
        {
            // If path is relative take %IGXLROOT% as the base directory
            if (!Path.IsPathRooted(path))
            {
                if (string.IsNullOrEmpty(RelativePath))
                {
                    // Exceptions handled by Path.GetFullPath
                    // ArgumentException path is a zero-length string, contains only white space, or contains one or more of the invalid characters defined in GetInvalidPathChars. -or- The system could not retrieve the absolute path.
                    // 
                    // SecurityException The caller does not have the required permissions.
                    // 
                    // ArgumentNullException path is null.
                    // 
                    // NotSupportedException path contains a colon (":") that is not part of a volume identifier (for example, "c:\"). 
                    // PathTooLongException The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.

                    // RelativePath is not passed so we would take the project path 
                    path = Path.GetFullPath(RelativePath);

                }
                else
                {
                    // Make sure the path is relative to the RelativePath and not our project directory
                    path = Path.Combine(RelativePath, path);
                }
            }

            // Exceptions from FileInfo Constructor:
            //   System.ArgumentNullException:
            //     fileName is null.
            //
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
            //
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
            //
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
            //
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
            FileInfo fileInfo = new FileInfo(path);

            // Exceptions using FileInfo.Length:
            //   System.IO.IOException:
            //     System.IO.FileSystemInfo.Refresh() cannot update the state of the file or
            //     directory.
            //
            //   System.IO.FileNotFoundException:
            //     The file does not exist.-or- The Length property is called for a directory.
            bool throwEx = fileInfo.Length == -1;

            // Exceptions using FileInfo.IsReadOnly:
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
            //     The file described by the current System.IO.FileInfo object is read-only.-or-
            //     This operation is not supported on the current platform.-or- The caller does
            //     not have the required permission.
            throwEx = fileInfo.IsReadOnly;

            if (!string.IsNullOrEmpty(Extension))
            {
                // Validate the Extension of the file.
                if (Path.GetExtension(path).Equals(Extension, StringComparison.InvariantCultureIgnoreCase))
                {
                    // Trim the Library Path
                    path = path.Trim();
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;

            }
        }
        catch (ArgumentNullException)
        {
            //   System.ArgumentNullException:
            //     fileName is null.
        }
        catch (System.Security.SecurityException)
        {
            //   System.Security.SecurityException:
            //     The caller does not have the required permission.
        }
        catch (ArgumentException)
        {
            //   System.ArgumentException:
            //     The file name is empty, contains only white spaces, or contains invalid characters.
        }
        catch (UnauthorizedAccessException)
        {
            //   System.UnauthorizedAccessException:
            //     Access to fileName is denied.
        }
        catch (PathTooLongException)
        {
            //   System.IO.PathTooLongException:
            //     The specified path, file name, or both exceed the system-defined maximum
            //     length. For example, on Windows-based platforms, paths must be less than
            //     248 characters, and file names must be less than 260 characters.
        }
        catch (NotSupportedException)
        {
            //   System.NotSupportedException:
            //     fileName contains a colon (:) in the middle of the string.
        }
        catch (FileNotFoundException)
        {
            // System.FileNotFoundException
            //  The exception that is thrown when an attempt to access a file that does not
            //  exist on disk fails.
        }
        catch (IOException)
        {
            //   System.IO.IOException:
            //     An I/O error occurred while opening the file.
        }
        catch (Exception)
        {
            // Unknown Exception. Might be due to wrong case or nulll checks.
        }
    }
    else
    {
        // Path contains invalid characters
    }
    return false;
}

9

Đây là một giải pháp thúc đẩy việc sử dụng Path.GetFullPath như được đề xuất trong câu trả lời của @SLaks .

Trong đoạn mã mà tôi đưa vào đây, hãy lưu ý rằng nó IsValidPath(string path)được thiết kế để người gọi không phải lo lắng về việc xử lý ngoại lệ .

Bạn cũng có thể thấy rằng phương pháp mà nó gọi, TryGetFullPath(...)cũng có giá trị riêng khi bạn muốn cố gắng tìm một con đường tuyệt đối một cách an toàn .

/// <summary>
/// Gets a value that indicates whether <paramref name="path"/>
/// is a valid path.
/// </summary>
/// <returns>Returns <c>true</c> if <paramref name="path"/> is a
/// valid path; <c>false</c> otherwise. Also returns <c>false</c> if
/// the caller does not have the required permissions to access
/// <paramref name="path"/>.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="TryGetFullPath"/>
public static bool IsValidPath(string path)
{
    string result;
    return TryGetFullPath(path, out result);
}

/// <summary>
/// Returns the absolute path for the specified path string. A return
/// value indicates whether the conversion succeeded.
/// </summary>
/// <param name="path">The file or directory for which to obtain absolute
/// path information.
/// </param>
/// <param name="result">When this method returns, contains the absolute
/// path representation of <paramref name="path"/>, if the conversion
/// succeeded, or <see cref="String.Empty"/> if the conversion failed.
/// The conversion fails if <paramref name="path"/> is null or
/// <see cref="String.Empty"/>, or is not of the correct format. This
/// parameter is passed uninitialized; any value originally supplied
/// in <paramref name="result"/> will be overwritten.
/// </param>
/// <returns><c>true</c> if <paramref name="path"/> was converted
/// to an absolute path successfully; otherwise, false.
/// </returns>
/// <seealso cref="Path.GetFullPath"/>
/// <seealso cref="IsValidPath"/>
public static bool TryGetFullPath(string path, out string result)
{
    result = String.Empty;
    if (String.IsNullOrWhiteSpace(path)) { return false; }
    bool status = false;

    try
    {
        result = Path.GetFullPath(path);
        status = true;
    }
    catch (ArgumentException) { }
    catch (SecurityException) { }
    catch (NotSupportedException) { }
    catch (PathTooLongException) { }

    return status;
}

6

Sử dụng mã này

string DirectoryName = "Sample Name For Directory Or File";
Path.GetInvalidFileNameChars()
  .Where(x => DirectoryName.Contains(x))
  .Count() > 0 || DirectoryName == "con"

4
Hơi mã ngắn hơn hoàn thành cùng một điều: Path.GetInvalidFileNameChars().Any(DirectoryName.Contains) || DirectoryName == "con"
bsegraves

2
@nawfal Thật vậy. Từ Đặt tên tệp, đường dẫn và không gian tên trên MSDN: "Không sử dụng các tên dành riêng sau cho tên của tệp: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 và LPT9. Ngoài ra, hãy tránh những tên này ngay sau phần mở rộng; ví dụ: NUL.txt không được khuyến nghị. Để biết thêm thông tin, hãy xem Không gian tên ".
DavidRR

"Giải pháp ngăn chặn danh sách đen" này không hoạt động trên mọi hệ thống cửa sổ, ví dụ như khi hình ảnh hiển thị: en.wikipedia.org/wiki/Mis Linh tinh_Symbols_and_Pictographs
Ngày

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

3

Tôi không gặp bất kỳ vấn đề nào với mã này:

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

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

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

    return isValid;
}

Ví dụ, những điều này sẽ trả về false:

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");
IsValidPath("abc");
IsValidPath("abc", false);

Và những điều này sẽ trả về true:

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", false);

0

Một giải pháp đơn giản hơn không phụ thuộc vào hệ điều hành.

public static class PathHelper
{
    public static void ValidatePath(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path).Delete();
    }
}

Sử dụng:

try
{
    PathHelper.ValidatePath(path);
}
catch(Exception e)
{
    // handle exception
}

Directory.CreateDirectory() sẽ tự động ném vào tất cả các trường hợp sau:

System.IO.IOException:
Thư mục được chỉ định bởi đường dẫn là một tệp. -hoặc- Tên mạng không được biết.

System.UnauthorizedAccessException:
Người gọi không có quyền cần thiết.

System.ArgumentException:
đường dẫn là một chuỗi có độ dài bằng 0, chỉ chứa khoảng trắng hoặc chứa một hoặc nhiều ký tự không hợp lệ. Bạn có thể truy vấn các ký tự không hợp lệ bằng cách sử dụng phương thức System.IO.Path.GetInvalidPathChars. -or- path có tiền tố hoặc chỉ chứa ký tự dấu hai chấm (:).

System.ArgumentNullException:
đường dẫn rỗng.

System.IO.PathTooLongException:
Đường dẫn được chỉ định, tên tệp hoặc cả hai đều vượt quá độ dài tối đa do hệ thống xác định.

System.IO.DirectoryNotFoundException:
Đường dẫn được chỉ định không hợp lệ (ví dụ: nó nằm trên một ổ đĩa chưa được ánh xạ).

System.NotSupportedException:
đường dẫn chứa ký tự dấu hai chấm (:) không phải là một phần của nhãn ổ đĩa ("C:").

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.