Làm cách nào để kiểm tra xem một chuỗi đã cho có phải là tên tệp hợp pháp / hợp lệ trong Windows không?


165

Tôi muốn bao gồm một chức năng đổi tên tập tin hàng loạt trong ứng dụng của tôi. Người dùng có thể nhập mẫu tên tệp đích và (sau khi thay thế một số ký tự đại diện trong mẫu) Tôi cần kiểm tra xem đó có phải là tên tệp hợp pháp trong Windows không. Tôi đã cố gắng sử dụng biểu thức chính quy như thế [a-zA-Z0-9_]+nhưng nó không bao gồm nhiều ký tự cụ thể theo quốc gia từ nhiều ngôn ngữ khác nhau (ví dụ: umlauts, v.v.). Cách tốt nhất để làm một kiểm tra như vậy là gì?


Tôi khuyên bạn nên sử dụng Regex được biên dịch tĩnh nếu bạn định sử dụng bất kỳ câu trả lời nào với Regex ..
AMissico

Câu trả lời:


100

Bạn có thể nhận được một danh sách các ký tự không hợp lệ từ Path.GetInvalidPathCharsGetInvalidFileNameChars.

CẬP NHẬT: Xem đề xuất của Steve Cooper về cách sử dụng chúng trong biểu thức chính quy.

CẬP NHẬT: Lưu ý rằng theo phần Ghi chú trong MSDN "Mảng được trả về từ phương thức này không được đảm bảo để chứa bộ ký tự hoàn chỉnh không hợp lệ trong tên tệp và thư mục." Câu trả lời được cung cấp bởi sixlettervaliabled đi vào chi tiết hơn.


11
Điều này không trả lời câu hỏi; có nhiều chuỗi chỉ bao gồm các ký tự hợp lệ (ví dụ: "....", "CON", chuỗi dài hàng trăm ký tự) không phải là tên tệp hợp lệ.
Dour High Arch

31
Bất cứ ai khác thất vọng rằng MS không cung cấp chức năng / API cấp hệ thống cho khả năng này thay vì mỗi nhà phát triển phải tự nấu giải pháp của mình? Tự hỏi liệu có một lý do rất tốt cho việc này hay chỉ là một sự giám sát về phần MS.
Thomas Nguyễn

@High Arch: Xem câu trả lời cho câu hỏi "Trong C # kiểm tra xem tên tệp có thể hợp lệ không (không tồn tại)". (Mặc dù một số kẻ thông minh đã đóng câu hỏi đó để ủng hộ câu hỏi này ...)
mmmmmmmm

129

Từ "Đặt tên tệp hoặc thư mục" của MSDN, đây là các quy ước chung cho tên tệp hợp pháp trong Windows:

Bạn có thể sử dụng bất kỳ ký tự nào trong trang mã hiện tại (Unicode / ANSI trên 127), ngoại trừ:

  • < > : " / \ | ? *
  • Các ký tự có biểu diễn số nguyên là 0-31 (nhỏ hơn không gian ASCII)
  • Bất kỳ ký tự nào khác mà hệ thống tệp đích không cho phép (giả sử, dấu chấm hoặc dấu cách)
  • Bất kỳ tên DOS nào: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT5, LPT LPT8, LPT9 (và tránh AUX.txt, v.v.)
  • Tên tập tin là tất cả các thời kỳ

Một số điều tùy chọn để kiểm tra:

  • Đường dẫn tệp (bao gồm tên tệp) có thể không có nhiều hơn 260 ký tự (không sử dụng \?\tiền tố)
  • Đường dẫn tệp Unicode (bao gồm tên tệp) có hơn 32.000 ký tự khi sử dụng \?\(lưu ý rằng tiền tố có thể mở rộng các thành phần thư mục và khiến nó vượt quá giới hạn 32.000)

8
+1 để bao gồm tên tệp dành riêng - những tên đã bị bỏ lỡ trong các câu trả lời trước.
SqlRyan

2
"AUX" là tên tệp hoàn toàn có thể sử dụng được nếu bạn sử dụng cú pháp "\\? \". Tất nhiên, các chương trình không sử dụng cú pháp đó có vấn đề thực sự với nó ... (Đã thử nghiệm trên XP)
user9876

9
Regex chính xác cho tất cả các điều kiện được đề cập ở trên là như sau:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
whywhyyy

4
@whywhy Tôi nghĩ bạn đã có thêm một khung mở trong Regex đó. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\. +) $) (\\ .. *)? $) | (([\ x00 - \\ x1f \\\\? *: \ "; | / <>]) +) | ([\\.] +)" làm việc cho tôi.
Wilky

4
Tôi đã đọc cùng một bài viết được đề cập trong câu trả lời này và nhận thấy qua thử nghiệm rằng COM0 và LPT0 cũng không được phép. @dlf cái này hoạt động với tên tệp bắt đầu bằng '.':^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr

67

Đối với .Net Framework trước 3.5, điều này sẽ hoạt động:

Kết hợp biểu thức chính quy sẽ giúp bạn có một số cách. Đây là một đoạn sử dụng System.IO.Path.InvalidPathCharshằng số;

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("[" 
          + Regex.Escape(System.IO.Path.InvalidPathChars) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

Đối với .Net Frameworks sau 3.0, điều này sẽ hoạt động:

http://msdn.microsoft.com/en-us/l Library / system.io.path.getinvalidpathchars (v = vs.90) .aspx

Kết hợp biểu thức chính quy sẽ giúp bạn có một số cách. Đây là một đoạn sử dụng System.IO.Path.GetInvalidPathChars()hằng số;

bool IsValidFilename(string testName)
{
    Regex containsABadCharacter = new Regex("["
          + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]");
    if (containsABadCharacter.IsMatch(testName)) { return false; };

    // other checks for UNC, drive-path format, etc

    return true;
}

Khi bạn biết điều đó, bạn cũng nên kiểm tra các định dạng khác nhau, ví dụ c:\my\drive\\server\share\dir\file.ext


Điều này không chỉ kiểm tra đường dẫn, không phải tên tệp?
Eugene Katz

30
chuỗi strTheseAreInvalidFileNameChars = chuỗi mới (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = new Regex ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
rao

2
Một nghiên cứu nhỏ từ mọi người sẽ làm việc kỳ diệu. Tôi đã cập nhật bài viết để phản ánh các thay đổi.
Erik Philips

1
Đoạn mã thứ 2 không biên dịch. "Không thể chuyển đổi từ char [] thành chuỗi
Paul Hunt

1
@AshkanMobayenKhiabani: UnlimitedPathChars đã lỗi thời nhưng GetInvalidPathChars thì không.
IvanH

25

Cố gắng sử dụng nó, và bẫy cho lỗi. Bộ được phép có thể thay đổi trên các hệ thống tệp hoặc trên các phiên bản Windows khác nhau. Nói cách khác, nếu bạn muốn biết nếu Windows thích tên đó, hãy đưa tên đó và để cho nó biết.


1
Đây dường như là người duy nhất kiểm tra tất cả các ràng buộc. Tại sao các câu trả lời khác được chọn trên này?
khoảng cách

5
@gap vì nó không hoạt động. Ví dụ: cố gắng truy cập CON thường sẽ thành công, mặc dù đó không phải là một tập tin thực sự.
Antimon

4
Mặc dù vậy, tốt hơn hết là tránh sử dụng bộ nhớ để ném Ngoại lệ, nếu có thể.
Owen Blacker

2
Ngoài ra, bạn có thể không có quyền truy cập nó; ví dụ để kiểm tra nó bằng cách viết, ngay cả khi bạn có thể đọc nó nếu nó tồn tại hoặc sẽ tồn tại.
CodeLurker

23

Lớp này làm sạch tên tập tin và đường dẫn; sử dụng nó như

var myCleanPath = PathSanitizer.SanitizeFilename(myBadPath, ' ');

Đây là mã;

/// <summary>
/// Cleans paths of invalid characters.
/// </summary>
public static class PathSanitizer
{
    /// <summary>
    /// The set of invalid filename characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidFilenameChars;
    /// <summary>
    /// The set of invalid path characters, kept sorted for fast binary search
    /// </summary>
    private readonly static char[] invalidPathChars;

    static PathSanitizer()
    {
        // set up the two arrays -- sorted once for speed.
        invalidFilenameChars = System.IO.Path.GetInvalidFileNameChars();
        invalidPathChars = System.IO.Path.GetInvalidPathChars();
        Array.Sort(invalidFilenameChars);
        Array.Sort(invalidPathChars);

    }

    /// <summary>
    /// Cleans a filename of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizeFilename(string input, char errorChar)
    {
        return Sanitize(input, invalidFilenameChars, errorChar);
    }

    /// <summary>
    /// Cleans a path of invalid characters
    /// </summary>
    /// <param name="input">the string to clean</param>
    /// <param name="errorChar">the character which replaces bad characters</param>
    /// <returns></returns>
    public static string SanitizePath(string input, char errorChar)
    {
        return Sanitize(input, invalidPathChars, errorChar);
    }

    /// <summary>
    /// Cleans a string of invalid characters.
    /// </summary>
    /// <param name="input"></param>
    /// <param name="invalidChars"></param>
    /// <param name="errorChar"></param>
    /// <returns></returns>
    private static string Sanitize(string input, char[] invalidChars, char errorChar)
    {
        // null always sanitizes to null
        if (input == null) { return null; }
        StringBuilder result = new StringBuilder();
        foreach (var characterToTest in input)
        {
            // we binary search for the character in the invalid set. This should be lightning fast.
            if (Array.BinarySearch(invalidChars, characterToTest) >= 0)
            {
                // we found the character in the array of 
                result.Append(errorChar);
            }
            else
            {
                // the character was not found in invalid, so it is valid.
                result.Append(characterToTest);
            }
        }

        // we're done.
        return result.ToString();
    }

}

1
câu trả lời của bạn có thể phù hợp hơn ở đây: stackoverflow.com/questions/146134/õ
nawfal

22

Đây là những gì tôi sử dụng:

    public static bool IsValidFileName(this string expression, bool platformIndependent)
    {
        string sPattern = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$";
        if (platformIndependent)
        {
           sPattern = @"^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?))\\)*[^\\/:\*\?""\|<>\. ](([^\\/:\*\?""\|<>\. ])|([^\\/:\*\?""\|<>]*[^\\/:\*\?""\|<>\. ]))?$";
        }
        return (Regex.IsMatch(expression, sPattern, RegexOptions.CultureInvariant));
    }

Mẫu đầu tiên tạo một biểu thức chính quy chỉ chứa các tên và ký tự tệp không hợp lệ / không hợp lệ cho các nền tảng Windows. Cái thứ hai làm tương tự nhưng đảm bảo rằng tên đó là hợp pháp cho bất kỳ nền tảng nào.


4
regex sPotype không cho phép các tệp bắt đầu bằng ký tự dấu chấm. Nhưng MSDN nói "có thể chấp nhận chỉ định một khoảng thời gian là ký tự đầu tiên của tên. Ví dụ:" .temp "". Tôi sẽ xóa "\ .. *" để đặt tên tệp chính xác .gitignore :)
yar_shukan

. ký và không cho phép không gian hoặc dấu chấm ở cuối (không cho phép các tên chỉ bao gồm các dấu chấm):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr

Điều này không thành công cho tất cả các tập tin tôi đã thử nghiệm. chạy nó cho C: \ Windows \ System32 \ msxml6.dll báo cáo sai.
magicandre1981

@ magicandre1981 Bạn cần chỉ cung cấp cho nó tên tệp chứ không phải đường dẫn đủ điều kiện.
Scott Dorman

ok, nhưng tôi cần kiểm tra xem đường dẫn đầy đủ có hợp lệ không. Tôi đã sử dụng một giải pháp khác nhau.
magicandre1981

18

Một trường hợp cần lưu ý, điều làm tôi ngạc nhiên khi lần đầu tiên tôi phát hiện ra điều đó: Windows cho phép các ký tự không gian hàng đầu trong tên tệp! Ví dụ: sau đây là tất cả các tên tệp hợp pháp và riêng biệt trên Windows (trừ dấu ngoặc kép):

"file.txt"
" file.txt"
"  file.txt"

Một điểm trừ từ điều này: Hãy thận trọng khi viết mã cắt các khoảng trắng hàng đầu / theo dõi từ một chuỗi tên tệp.


10

Đơn giản hóa câu trả lời của Eugene Katz:

bool IsFileNameCorrect(string fileName){
    return !fileName.Any(f=>Path.GetInvalidFileNameChars().Contains(f))
}

Hoặc là

bool IsFileNameCorrect(string fileName){
    return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}

Ý của bạn là: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Chứa (f));" ?
Jack Griffin

@JackGriffin Tất nhiên rồi! Cảm ơn bạn đã chu đáo.
tmt

Mặc dù mã này rất hay để đọc, chúng ta nên tính đến các nội dung xin lỗi của Path.GetInvalidFileNameChars. Hãy xem tại đây: Referenceource.microsoft.com/#mscorlib/system/io/path.cs,289 - cho mỗi ký tự của bạn fileName, một bản sao của mảng được tạo.
Piotr Zierhoffer

"DD: \\\\\ AAA ..... AAAA". Không hợp lệ, nhưng đối với mã của bạn, nó là.
Ciccio Pasticcio

8

Microsoft Windows: Windows kernel cấm sử dụng các ký tự trong phạm vi 1-31 (tức là 0x01-0x1F) và các ký tự "*: <>? \ |. Mặc dù NTFS cho phép mỗi thành phần đường dẫn (thư mục hoặc tên tệp) dài 255 ký tự và đường dẫn dài tới khoảng 32767 ký tự, nhân Windows chỉ hỗ trợ các đường dẫn dài tối đa 259 ký tự. Ngoài ra, Windows cấm sử dụng tên thiết bị MS-DOS AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL và PRN, cũng như các tên này với bất kỳ tiện ích mở rộng nào (ví dụ: AUX.txt), ngoại trừ khi sử dụng Đường dẫn UNC dài (ví dụ: \. \ C: \ nul.txt hoặc \? \ D: \ aux \ con). Linux, ví dụ, cho phép sử dụng "*: <>? \ | ngay cả trong NTFS.

Nguồn: http://en.wikipedia.org/wiki/Filename


1
Tôi có thể tạo một tệp có tên "CLOCK $" tốt. Windows 7.
rory.ap

7

Thay vì bao gồm rõ ràng tất cả các ký tự có thể, bạn có thể thực hiện một regex để kiểm tra sự hiện diện của các ký tự không hợp lệ và sau đó báo cáo lỗi. Lý tưởng nhất là ứng dụng của bạn nên đặt tên cho các tệp chính xác như người dùng mong muốn và chỉ khóc khi gặp phải lỗi.


6

Câu hỏi đặt ra là bạn đang cố gắng xác định xem tên đường dẫn có phải là đường dẫn cửa sổ hợp pháp hay không, nếu nó hợp pháp trên hệ thống nơi mã đang chạy.? Tôi nghĩ rằng cái sau quan trọng hơn, vì vậy cá nhân tôi có thể phân tách đường dẫn đầy đủ và thử sử dụng _mkdir để tạo thư mục mà tệp thuộc về, sau đó thử tạo tệp.

Bằng cách này, bạn biết không chỉ nếu đường dẫn chỉ chứa các ký tự cửa sổ hợp lệ, mà nếu nó thực sự đại diện cho một đường dẫn có thể được viết bởi quá trình này.


6

Tôi sử dụng điều này để loại bỏ các ký tự không hợp lệ trong tên tệp mà không đưa ra ngoại lệ:

private static readonly Regex InvalidFileRegex = new Regex(
    string.Format("[{0}]", Regex.Escape(@"<>:""/\|?*")));

public static string SanitizeFileName(string fileName)
{
    return InvalidFileRegex.Replace(fileName, string.Empty);
}

5

Ngoài ra CON, PRN, AUX, NUL, COM # và một số tên khác không bao giờ là tên tệp hợp pháp trong bất kỳ thư mục có bất kỳ tiện ích mở rộng nào.


1
Đây chỉ là một nửa của sự thật. Bạn có thể tạo các tệp có các tên này nếu gọi phiên bản unicode của CreatFile (tiền tố tên tệp bằng "\\? \").
Werner Henze

Tuyên bố này không đầy đủ và bỏ lỡ LPT #
Thomas Weller

4

Để bổ sung cho các câu trả lời khác, đây là một vài trường hợp cạnh bổ sung mà bạn có thể muốn xem xét.


3

Từ MSDN , đây là danh sách các ký tự không được phép:

Sử dụng hầu hết mọi ký tự trong trang mã hiện tại cho một tên, bao gồm các ký tự và ký tự Unicode trong bộ ký tự mở rộng (128 trừ255), ngoại trừ các mục sau:

  • Các ký tự dành riêng sau đây không được phép: <>: "/ \ |? *
  • Các ký tự có biểu diễn số nguyên nằm trong phạm vi từ 0 đến 31 không được phép.
  • Bất kỳ ký tự nào khác mà hệ thống tệp đích không cho phép.

2

Ngoài ra hệ thống tập tin đích là quan trọng.

Trong NTFS, một số tệp không thể được tạo trong các thư mục cụ thể. Khởi động EG $ trong root


2
Chắc chắn đó không phải là do quy tắc đặt tên NTFS, mà chỉ vì một tệp được gọi $Bootđã tồn tại trong thư mục?
Christian Hayter

2

Đây là một câu hỏi đã được trả lời, nhưng chỉ vì mục đích "Các lựa chọn khác", đây là một câu hỏi không lý tưởng:

(không lý tưởng vì sử dụng Ngoại lệ làm kiểm soát luồng là "Điều xấu", nói chung)

public static bool IsLegalFilename(string name)
{
    try 
    {
        var fileInfo = new FileInfo(name);
        return true;
    }
    catch
    {
        return false;
    }
}

Ví dụ của bạn không hoạt động đối với tệp CON (C: \ temp \ CON).
tcbrazil

Nhưng không phải 'C: \ temp \ CON' là tên tệp hợp lệ? Tại sao không?
Đánh dấu A. Donohoe

@MarqueIV - không, nó không hợp lệ. Đọc tất cả các câu trả lời và ý kiến ​​ở trên, hoặc tự mình thử và xem.
rory.ap

@Jer, "/ example" không hợp pháp, nhưng phương thức của bạn trả về true.
rory.ap

Aaaah ... Tôi đã bỏ lỡ phần 'CON'. Tên chính nó là hợp lệ từ một quan điểm chuỗi (đó là những gì tôi đã đề cập), nhưng tôi thấy bây giờ CON là một tên dành riêng, làm cho nó không hợp lệ từ quan điểm của Windows. Lỗi của tôi.
Đánh dấu A. Donohoe

2

Biểu thức thông thường là quá mức cần thiết cho tình huống này. Bạn có thể sử dụng String.IndexOfAny()phương thức kết hợp với Path.GetInvalidPathChars()Path.GetInvalidFileNameChars() .

Cũng lưu ý rằng cả hai Path.GetInvalidXXX()phương thức đều sao chép một mảng bên trong và trả về bản sao. Vì vậy, nếu bạn sẽ làm điều này rất nhiều (hàng nghìn và hàng nghìn lần), bạn có thể lưu trữ một bản sao của mảng ký tự không hợp lệ để sử dụng lại.


2

Nếu bạn chỉ cố kiểm tra xem một chuỗi giữ tên / đường dẫn tệp của bạn có bất kỳ ký tự không hợp lệ nào không, thì phương pháp nhanh nhất tôi tìm thấy là sử dụng Split()để chia tên tệp thành một mảng các phần bất cứ nơi nào có ký tự không hợp lệ. Nếu kết quả chỉ là một mảng 1, không có ký tự không hợp lệ. :-)

var nameToTest = "Best file name \"ever\".txt";
bool isInvalidName = nameToTest.Split(System.IO.Path.GetInvalidFileNameChars()).Length > 1;

var pathToTest = "C:\\My Folder <secrets>\\";
bool isInvalidPath = pathToTest.Split(System.IO.Path.GetInvalidPathChars()).Length > 1;

Tôi đã thử chạy phương thức này và các phương pháp khác được đề cập ở trên trên tên tệp / đường dẫn 1.000.000 lần trong LinqPad.

Sử dụng Split()chỉ ~ 850ms.

Sử dụng Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")là khoảng 6 giây.

Các biểu thức chính quy phức tạp hơn NHIỀU tệ hơn, cũng như một số tùy chọn khác, như sử dụng các phương thức khác nhau trên Pathlớp để lấy tên tệp và để xác thực nội bộ của chúng thực hiện công việc (rất có thể là do xử lý ngoại lệ).

Cấp cho nó không thường xuyên bạn cần xác thực 1 triệu tên tệp, do đó, một lần lặp duy nhất là tốt cho hầu hết các phương thức này. Nhưng nó vẫn khá hiệu quả và hiệu quả nếu bạn chỉ tìm kiếm các ký tự không hợp lệ.


1

nhiều câu trả lời trong số này sẽ không hoạt động nếu tên tệp quá dài và chạy trên môi trường Windows 10 trước. Tương tự, hãy suy nghĩ về những gì bạn muốn làm với các khoảng thời gian - cho phép dẫn đầu hoặc theo dõi là hợp lệ về mặt kỹ thuật, nhưng có thể tạo ra vấn đề nếu bạn không muốn tệp khó nhìn thấy hoặc xóa tương ứng.

Đây là thuộc tính xác thực tôi đã tạo để kiểm tra tên tệp hợp lệ.

public class ValidFileNameAttribute : ValidationAttribute
{
    public ValidFileNameAttribute()
    {
        RequireExtension = true;
        ErrorMessage = "{0} is an Invalid Filename";
        MaxLength = 255; //superseeded in modern windows environments
    }
    public override bool IsValid(object value)
    {
        //http://stackoverflow.com/questions/422090/in-c-sharp-check-that-filename-is-possibly-valid-not-that-it-exists
        var fileName = (string)value;
        if (string.IsNullOrEmpty(fileName)) { return true;  }
        if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 ||
            (!AllowHidden && fileName[0] == '.') ||
            fileName[fileName.Length - 1]== '.' ||
            fileName.Length > MaxLength)
        {
            return false;
        }
        string extension = Path.GetExtension(fileName);
        return (!RequireExtension || extension != string.Empty)
            && (ExtensionList==null || ExtensionList.Contains(extension));
    }
    private const string _sepChar = ",";
    private IEnumerable<string> ExtensionList { get; set; }
    public bool AllowHidden { get; set; }
    public bool RequireExtension { get; set; }
    public int MaxLength { get; set; }
    public string AllowedExtensions {
        get { return string.Join(_sepChar, ExtensionList); } 
        set {
            if (string.IsNullOrEmpty(value))
            { ExtensionList = null; }
            else {
                ExtensionList = value.Split(new char[] { _sepChar[0] })
                    .Select(s => s[0] == '.' ? s : ('.' + s))
                    .ToList();
            }
    } }

    public override bool RequiresValidationContext => false;
}

và các bài kiểm tra

[TestMethod]
public void TestFilenameAttribute()
{
    var rxa = new ValidFileNameAttribute();
    Assert.IsFalse(rxa.IsValid("pptx."));
    Assert.IsFalse(rxa.IsValid("pp.tx."));
    Assert.IsFalse(rxa.IsValid("."));
    Assert.IsFalse(rxa.IsValid(".pp.tx"));
    Assert.IsFalse(rxa.IsValid(".pptx"));
    Assert.IsFalse(rxa.IsValid("pptx"));
    Assert.IsFalse(rxa.IsValid("a/abc.pptx"));
    Assert.IsFalse(rxa.IsValid("a\\abc.pptx"));
    Assert.IsFalse(rxa.IsValid("c:abc.pptx"));
    Assert.IsFalse(rxa.IsValid("c<abc.pptx"));
    Assert.IsTrue(rxa.IsValid("abc.pptx"));
    rxa = new ValidFileNameAttribute { AllowedExtensions = ".pptx" };
    Assert.IsFalse(rxa.IsValid("abc.docx"));
    Assert.IsTrue(rxa.IsValid("abc.pptx"));
}

1

Nỗ lực của tôi:

using System.IO;

static class PathUtils
{
  public static string IsValidFullPath([NotNull] string fullPath)
  {
    if (string.IsNullOrWhiteSpace(fullPath))
      return "Path is null, empty or white space.";

    bool pathContainsInvalidChars = fullPath.IndexOfAny(Path.GetInvalidPathChars()) != -1;
    if (pathContainsInvalidChars)
      return "Path contains invalid characters.";

    string fileName = Path.GetFileName(fullPath);
    if (fileName == "")
      return "Path must contain a file name.";

    bool fileNameContainsInvalidChars = fileName.IndexOfAny(Path.GetInvalidFileNameChars()) != -1;
    if (fileNameContainsInvalidChars)
      return "File name contains invalid characters.";

    if (!Path.IsPathRooted(fullPath))
      return "The path must be absolute.";

    return "";
  }
}

Điều này là không hoàn hảo vì Path.GetInvalidPathCharskhông trả về bộ ký tự hoàn chỉnh không hợp lệ trong tên tệp và thư mục và tất nhiên có nhiều sự tinh tế hơn.

Vì vậy, tôi sử dụng phương pháp này như là một bổ sung:

public static bool TestIfFileCanBeCreated([NotNull] string fullPath)
{
  if (string.IsNullOrWhiteSpace(fullPath))
    throw new ArgumentException("Value cannot be null or whitespace.", "fullPath");

  string directoryName = Path.GetDirectoryName(fullPath);
  if (directoryName != null) Directory.CreateDirectory(directoryName);
  try
  {
    using (new FileStream(fullPath, FileMode.CreateNew)) { }
    File.Delete(fullPath);
    return true;
  }
  catch (IOException)
  {
    return false;
  }
}

Nó cố gắng tạo tập tin và trả về false nếu có ngoại lệ. Tất nhiên, tôi cần tạo tập tin nhưng tôi nghĩ đó là cách an toàn nhất để làm điều đó. Cũng xin lưu ý rằng tôi không xóa các thư mục đã được tạo.

Bạn cũng có thể sử dụng phương thức đầu tiên để thực hiện xác nhận cơ bản và sau đó xử lý cẩn thận các ngoại lệ khi đường dẫn được sử dụng.


0

Tôi đề nghị chỉ sử dụng Path.GetFullPath ()

string tagetFileFullNameToBeChecked;
try
{
  Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
  // invalid chars found
}

Thêm một số lời giải thích với câu trả lời về cách câu trả lời này giúp OP khắc phục vấn đề hiện tại
ρяσѕρєя K

Xem tài liệu trong MSDN cho AugumentExcpetion, nó đọc: đường dẫn là một chuỗi có độ dài bằng không, 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.
Tony Sun

Về lý thuyết (theo các tài liệu), điều này sẽ hoạt động, mặc dù ít nhất là trong .NET Core 3.1, nhưng không.
Michel Jansson

0

Tôi có ý tưởng này từ một người nào đó. - không biết ai. Hãy để hệ điều hành làm việc nặng.

public bool IsPathFileNameGood(string fname)
{
    bool rc = Constants.Fail;
    try
    {
        this._stream = new StreamWriter(fname, true);
        rc = Constants.Pass;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Problem opening file");
        rc = Constants.Fail;
    }
    return rc;
}

0

Kiểm tra này

static bool IsValidFileName(string name)
{
    return
        !string.IsNullOrWhiteSpace(name) &&
        name.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 &&
        !Path.GetFullPath(name).StartsWith(@"\\.\");
}

lọc ra tên với ký tự không hợp lệ ( <>:"/\|?*và ASCII 0-31), cũng như các thiết bị hệ điều hành DOS bảo lưu ( CON, NUL, COMx). Nó cho phép các không gian hàng đầu và tất cả các tên chấm, phù hợp với Path.GetFullPath. (Tạo tập tin với không gian hàng đầu thành công trên hệ thống của tôi).


Đã sử dụng .NET Framework 4.7.1, đã thử nghiệm trên Windows 7.


0

Một lớp lót để xác minh các ký tự ảo trong chuỗi:

public static bool IsValidFilename(string testName) => !Regex.IsMatch(testName, "[" + Regex.Escape(new string(System.IO.Path.InvalidPathChars)) + "]");

0

Theo tôi, câu trả lời thích hợp duy nhất cho câu hỏi này là cố gắng sử dụng đường dẫn và để hệ điều hành và hệ thống tập tin xác nhận nó. Mặt khác, bạn chỉ thực hiện lại (và có thể là kém) tất cả các quy tắc xác thực mà HĐH và hệ thống tệp đã sử dụng và nếu các quy tắc đó được thay đổi trong tương lai, bạn sẽ phải thay đổi mã của mình để khớp với chúng.


-1

Cửa sổ tên tập tin là khá unrestrictive, vì vậy thực sự nó có thể thậm chí không có nhiều của một vấn đề. Các ký tự không được Windows cho phép là:

\ / : * ? " < > |

Bạn có thể dễ dàng viết một biểu thức để kiểm tra xem những ký tự đó có mặt không. Mặc dù vậy, một giải pháp tốt hơn là thử và đặt tên cho các tệp theo ý muốn của người dùng và thông báo cho họ khi tên tệp không bị dính.


Ngoài ra các ký tự <= 31 bị cấm.
Antimon
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.