ฉันจะตรวจสอบว่าสตริงที่กำหนดเป็นชื่อไฟล์ทางกฎหมาย / ที่ถูกต้องใน Windows ได้อย่างไร?


165

ฉันต้องการรวมฟังก์ชั่นการเปลี่ยนชื่อไฟล์แบทช์ในแอปพลิเคชันของฉัน ผู้ใช้สามารถพิมพ์รูปแบบชื่อไฟล์ปลายทางและ (หลังจากแทนที่อักขระตัวแทนบางตัวในรูปแบบ) ฉันต้องตรวจสอบว่าเป็นชื่อไฟล์ทางกฎหมายใน Windows หรือไม่ ฉันพยายามที่จะใช้การแสดงออกปกติเช่น[a-zA-Z0-9_]+แต่มันไม่ได้รวมตัวละครเฉพาะชาติจำนวนมากจากภาษาต่างๆ (เช่น umlauts และอื่น ๆ ) วิธีที่ดีที่สุดในการทำเช็คดังกล่าวคืออะไร?


ผมขอแนะนำให้ใช้คงที่รวบรวม Regex ถ้าคุณจะใช้คำตอบที่มี Regex ..
AMissico

คำตอบ:


100

คุณจะได้รับรายการของตัวอักษรที่ไม่ถูกต้องจากและPath.GetInvalidPathCharsGetInvalidFileNameChars

UPD:ดูคำแนะนำของ Steve Cooperเกี่ยวกับวิธีใช้สิ่งเหล่านี้ในการแสดงออกปกติ

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


11
สิ่งนี้ไม่ตอบคำถาม มีสตริงจำนวนมากที่ประกอบด้วยอักขระที่ถูกต้องเท่านั้น (เช่น ".... ", "CON", สตริงยาวร้อยตัวอักษร) ที่ไม่ใช่ชื่อไฟล์ที่ถูกต้อง
Dour High Arch

31
มีใครผิดหวังบ้างที่ MS ไม่ได้จัดเตรียมฟังก์ชั่นระดับระบบ / API สำหรับความสามารถนี้แทนที่จะเป็นนักพัฒนาแต่ละคนจะต้องปรุงแก้ปัญหาด้วยตนเองหรือไม่? สงสัยว่ามีเหตุผลที่ดีสำหรับเรื่องนี้หรือเพียงแค่การกำกับดูแลในส่วนของ MS
โทมัสเหงียน

@ สูง Arch: ดูคำตอบสำหรับคำถาม "ใน C # ตรวจสอบว่าชื่อไฟล์นั้นอาจถูกต้อง (ไม่ใช่ที่มีอยู่)" (แม้ว่าผู้ชายที่ฉลาดบางคนก็ปิดคำถามนี้เพื่อที่จะสนับสนุนคนนี้ ... )
mmmmmmmm

129

จาก"การตั้งชื่อไฟล์หรือไดเรกทอรี" ของ MSDNนี่คือการประชุมทั่วไปสำหรับชื่อไฟล์ที่ถูกกฎหมายภายใต้ Windows:

คุณสามารถใช้อักขระใด ๆ ในหน้ารหัสปัจจุบัน (Unicode / ANSI ด้านบน 127) ยกเว้น:

  • < > : " / \ | ? *
  • อักขระที่มีการแทนค่าจำนวนเต็ม 0-31 (น้อยกว่า ASCII space)
  • อักขระอื่นใดที่ระบบไฟล์เป้าหมายไม่อนุญาต (พูดระยะเวลาต่อท้ายหรือเว้นวรรค)
  • ชื่อ DOS ใด ๆ : CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM8, LPT0, LPT1, LPT2, LPT5, LPT5, LPT6, LPT7 LPT8, LPT9 (และหลีกเลี่ยง AUX.txt เป็นต้น)
  • ชื่อไฟล์เป็นระยะเวลาทั้งหมด

สิ่งที่เป็นตัวเลือกในการตรวจสอบ:

  • เส้นทางไฟล์ (รวมถึงชื่อไฟล์) อาจมีอักขระไม่เกิน 260 ตัว (ซึ่งไม่ได้ใช้\?\คำนำหน้า)
  • พา ธ ไฟล์ Unicode (รวมถึงชื่อไฟล์) ที่มีมากกว่า 32,000 ตัวอักษรเมื่อใช้งาน\?\(โปรดทราบว่าคำนำหน้าอาจขยายองค์ประกอบของไดเรกทอรีและทำให้เกินขีด จำกัด 32,000)

8
+1 สำหรับการรวมชื่อไฟล์ที่สงวนไว้ - ที่ไม่ได้รับคำตอบก่อนหน้านี้
SqlRyan

2
"AUX" เป็นชื่อไฟล์ที่สามารถใช้งานได้อย่างสมบูรณ์หากคุณใช้ไวยากรณ์ "\\? \" แน่นอนว่าโปรแกรมที่ไม่ได้ใช้ไวยากรณ์นั้นมีปัญหาจริงในการจัดการกับมัน ... (ทดสอบบน XP)
user9876

9
regex ที่ถูกต้องสำหรับเงื่อนไขเหล่านี้ทั้งหมดที่กล่าวถึงข้างต้นมีดังนี้:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
ทำไมเมื่อ

4
@whywhywhy ฉันคิดว่าคุณมีวงเล็บเปิดพิเศษใน Regex นั้น "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\ +) $) (\\ .. *) $.?) | (([\\ x00 - \\ x1f \\\\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" ได้ผลสำหรับฉัน
กี้

4
ฉันอ่านบทความเดียวกันที่กล่าวถึงในคำตอบนี้และพบว่าผ่านการทดลองว่า COM0 และ LPT0 นั้นไม่ได้รับอนุญาตด้วย @dlf อันนี้ทำงานกับชื่อไฟล์ที่ขึ้นต้นด้วย '.':^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr

67

สำหรับ. Net Frameworks ก่อนหน้า 3.5จะสามารถทำงานได้:

การจับคู่นิพจน์ทั่วไปควรช่วยคุณ นี่เป็นตัวอย่างการใช้System.IO.Path.InvalidPathCharsค่าคงที่

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

สำหรับ. Net Frameworks หลังจาก 3.0สิ่งนี้ควรใช้งานได้:

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

การจับคู่นิพจน์ทั่วไปควรช่วยคุณ นี่คือตัวอย่างข้อมูลโดยใช้System.IO.Path.GetInvalidPathChars()ค่าคงที่

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

เมื่อคุณทราบแล้วคุณควรตรวจสอบรูปแบบอื่นเช่นc:\my\driveและ\\server\share\dir\file.ext


สิ่งนี้ไม่เพียงทดสอบเส้นทางไม่ใช่ชื่อไฟล์ใช่หรือไม่
Eugene Katz

30
สตริง strTheseAreInvalidFileNameChars = สตริงใหม่ (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = ใหม่ Regex ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
rao

2
การวิจัยเพียงเล็กน้อยจากผู้คนก็น่าอัศจรรย์ ฉันได้อัปเดตโพสต์เพื่อให้สอดคล้องกับการเปลี่ยนแปลง
Erik Philips

1
โค้ดที่สองไม่ได้รวบรวม "ไม่สามารถแปลงจาก char [] เป็น string
Paul Hunt

1
@AshkanMobayenKhiabani: InvalidPathChars ล้าสมัย แต่ GetInvalidPathChars ไม่
IvanH

25

ลองใช้และดักจับข้อผิดพลาด ชุดที่อนุญาตอาจมีการเปลี่ยนแปลงในระบบไฟล์หรือใน Windows รุ่นต่าง ๆ กล่าวอีกนัยหนึ่งถ้าคุณต้องการทราบว่า Windows ชอบชื่อให้ส่งชื่อและแจ้งให้คุณทราบ


1
นี่ดูเหมือนจะเป็นสิ่งเดียวที่ทดสอบกับข้อ จำกัด ทั้งหมด เหตุใดจึงเลือกคำตอบอื่นมากกว่านี้
ช่องว่าง

5
@gap เพราะมันไม่ได้ผลเสมอไป ตัวอย่างเช่นการพยายามเข้าถึง CON มักจะประสบความสำเร็จแม้ว่าจะไม่ใช่ไฟล์จริงก็ตาม
พลวง

4
มันจะดีกว่าเสมอเพื่อหลีกเลี่ยงค่าใช้จ่ายหน่วยความจำของการขว้างข้อยกเว้นถ้าเป็นไปได้
Owen Blacker

2
นอกจากนี้คุณอาจไม่มีสิทธิ์ในการเข้าถึง เช่นเพื่อทดสอบโดยการเขียนแม้ว่าคุณจะสามารถอ่านได้ถ้ามันมีหรือจะมีอยู่
CodeLurker

23

ชั้นนี้ทำความสะอาดชื่อไฟล์และเส้นทาง ใช้มันเหมือน

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

นี่คือรหัส;

/// <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
คำตอบของคุณน่าจะเหมาะสมกว่าที่นี่: stackoverflow.com/questions/146134/…
nawfal

22

นี่คือสิ่งที่ฉันใช้:

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

รูปแบบแรกสร้างนิพจน์ทั่วไปที่มีชื่อไฟล์และอักขระที่ไม่ถูกต้อง / ผิดกฎหมายสำหรับแพลตฟอร์ม Windows เท่านั้น ตัวที่สองทำเหมือนกัน แต่รับรองว่าชื่อนั้นถูกกฎหมายสำหรับแพลตฟอร์มใด ๆ


4
sPattern regex ไม่อนุญาตให้ใช้ไฟล์ที่ขึ้นต้นด้วยอักขระแบบมีระยะเวลา แต่MSDN บอกว่า "เป็นที่ยอมรับได้ในการระบุจุดเป็นอักขระตัวแรกของชื่อตัวอย่างเช่น" .temp "" ฉันจะลบ "\ .. *" เพื่อสร้างชื่อไฟล์. gitignore ให้ถูกต้อง :)
yar_shukan

(ฉันทำให้ดีขึ้นแบบนี้ไปเรื่อย ๆ และลบความคิดเห็นก่อนหน้านี้ที่ฉันทิ้งไว้) อันนี้ดีกว่าคำตอบของ regex เพราะมันอนุญาตให้ ".gitignore", "..asdf", ไม่อนุญาตให้ '<' และ '>' หรือเยน ลงชื่อและไม่อนุญาตให้มีช่องว่างหรือจุดสิ้นสุดในตอนท้าย (ซึ่งไม่อนุญาตให้ใช้ชื่อที่ประกอบด้วยเฉพาะจุด):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr

สิ่งนี้ล้มเหลวสำหรับไฟล์ทั้งหมดที่ฉันทดสอบ เรียกใช้สำหรับ C: \ Windows \ System32 \ msxml6.dll รายงานเท็จ
magicandre1981

@ magicandre1981 คุณต้องตั้งชื่อไฟล์ไม่ใช่พา ธ ที่ผ่านการรับรองโดยสมบูรณ์
Scott Dorman

ตกลง แต่ฉันต้องตรวจสอบว่าเส้นทางแบบเต็มใช้ได้หรือไม่ ตอนนี้ฉันใช้โซลูชันอื่น
magicandre1981

18

กรณีมุมหนึ่งที่ต้องจำซึ่งทำให้ฉันประหลาดใจเมื่อฉันพบครั้งแรกเกี่ยวกับมัน: Windows อนุญาตให้มีอักขระช่องว่างนำในชื่อไฟล์! ตัวอย่างเช่นต่อไปนี้เป็นชื่อไฟล์ทั้งหมดที่ถูกกฎหมายและแตกต่างบน Windows (ลบเครื่องหมายคำพูด):

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

สิ่งหนึ่งที่เป็นไปได้จากสิ่งนี้: ใช้ความระมัดระวังเมื่อเขียนโค้ดที่จดจ้องช่องว่างนำหน้า / ต่อท้ายจากสตริงชื่อไฟล์


10

ทำให้คำตอบของ Eugene Katz ง่ายขึ้น:

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

หรือ

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

คุณหมายถึง: "return! fileName.Any (f => Path.GetInvalidFileNameChars (). ประกอบด้วย (f));" ?
Jack Griffin

@ JackGriffin แน่นอน! ขอบคุณสำหรับความสนใจ
tmt

ในขณะที่รหัสนี้เป็นสิ่งที่ดีมากที่จะอ่านเราควรคำนึงถึง internals ขอโทษPath.GetInvalidFileNameCharsด้วย ลองดูที่นี่: Referencesource.microsoft.com/#mscorlib/system/io/path.cs,289 - สำหรับตัวละครแต่ละตัวของคุณfileNameโคลนของอาร์เรย์จะถูกสร้างขึ้น
Piotr Zierhoffer

"DD: \\\\\ AAA ..... AAAA" ไม่ถูกต้อง แต่สำหรับรหัสของคุณมันเป็น
Ciccio Pasticcio

8

Microsoft Windows: เคอร์เนล Windows ห้ามการใช้อักขระในช่วง 1-31 (เช่น 0x01-0x1F) และอักขระ "*: <>? \ | ถึงแม้ว่า NTFS จะอนุญาตให้แต่ละองค์ประกอบพา ธ (ไดเรกทอรีหรือชื่อไฟล์) มีความยาว 255 ตัวและ พา ธ ยาวประมาณ 32767 ตัวอักษรเคอร์เนลของ Windows รองรับเฉพาะพา ธ ที่ยาวไม่เกิน 259 ตัวอักษรนอกจากนี้ Windows ยังห้ามการใช้ชื่ออุปกรณ์ MS-DOS ชื่อ AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT7, LPT8, LPT9, NUL และ PRN รวมถึงชื่อเหล่านี้ด้วยส่วนขยายใด ๆ (เช่น AUX.txt) เส้นทาง UNC แบบยาว (เช่น \. \ C: \ nul.txt หรือ \? \ D: \ aux \ con) (อันที่จริง CLOCK $ อาจถูกใช้หากมีการขยายเวลา) ข้อ จำกัด เหล่านี้ใช้ได้กับ Windows เท่านั้น - ตัวอย่างเช่น Linux อนุญาตให้ใช้ "*: <>? \ | แม้ใน NTFS

ที่มา: http://en.wikipedia.org/wiki/Filename


1
ฉันสามารถสร้างไฟล์ชื่อ "CLOCK $" ได้ดี Windows 7
rory.ap

7

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


6

คำถามคือคุณพยายามที่จะตรวจสอบว่าชื่อเส้นทางเป็นเส้นทาง windows ถูกกฎหมายหรือว่าเป็นกฎหมายในระบบที่รหัสทำงาน ? ฉันคิดว่าอันหลังมีความสำคัญมากกว่าดังนั้นโดยส่วนตัวแล้วฉันอาจย่อยสลายพา ธ เต็มและลองใช้ _mkdir เพื่อสร้างไดเรกทอรีที่ไฟล์นั้นเป็นของอยู่จากนั้นลองสร้างไฟล์

วิธีนี้คุณจะรู้ได้ไม่เพียงว่าเส้นทางนั้นมีอักขระ windows ที่ถูกต้องเท่านั้น แต่ถ้ามันหมายถึงเส้นทางที่กระบวนการนี้สามารถเขียนได้


6

ฉันใช้สิ่งนี้เพื่อกำจัดตัวละครที่ไม่ถูกต้องในชื่อไฟล์โดยไม่ทิ้งข้อยกเว้น:

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

นอกจากนี้ CON, PRN, AUX, NUL, COM # และอื่น ๆ ไม่กี่ชื่อไฟล์ทางกฎหมายในไดเรกทอรีใด ๆ ที่มีนามสกุลใด ๆ


1
นี่เป็นเพียงครึ่งหนึ่งของความจริง คุณสามารถสร้างไฟล์ด้วยชื่อเหล่านี้หากเรียกใช้ CreateFile เวอร์ชัน unicode (นำหน้าชื่อไฟล์ด้วย "\\? \")
เวอร์เนอร์ Henze

คำสั่งนี้ไม่สมบูรณ์และพลาด LPT #
Thomas Weller

4

เพื่อเติมเต็มคำตอบอื่น ๆ ต่อไปนี้เป็นกรณีขอบเพิ่มเติมสองสามอย่างที่คุณอาจต้องการพิจารณา

  • Excel อาจมีปัญหาหากคุณบันทึกเวิร์กบุ๊กในไฟล์ที่ชื่อประกอบด้วยอักขระ '[' หรือ ']' ดูhttp://support.microsoft.com/kb/215205สำหรับรายละเอียด

  • Sharepoint มีข้อ จำกัด เพิ่มเติมทั้งหมด ดูhttp://support.microsoft.com/kb/905231สำหรับรายละเอียด


3

จากMSDNนี่คือรายการอักขระที่ไม่อนุญาต:

ใช้ตัวละครเกือบทุกตัวในหน้ารหัสปัจจุบันสำหรับชื่อรวมถึงตัวอักษร Unicode และตัวอักษรในชุดอักขระแบบขยาย (128–255) ยกเว้นตัวต่อไปนี้:

  • ห้ามใช้อักขระที่สงวนไว้ดังต่อไปนี้: <>: "/ \ |? *
  • ไม่อนุญาตให้ใช้อักขระที่มีการแทนค่าจำนวนเต็มตั้งแต่ศูนย์ถึง 31
  • อักขระอื่นใดที่ระบบไฟล์เป้าหมายไม่อนุญาต

2

นอกจากนี้ระบบไฟล์ปลายทางก็มีความสำคัญเช่นกัน

ภายใต้ NTFS ไฟล์บางไฟล์ไม่สามารถสร้างได้ในไดเรกทอรีเฉพาะ EG $ Boot ในรูท


2
แน่นอนว่าไม่ใช่เพราะกฎการตั้งชื่อ NTFS แต่เพียงเพราะไฟล์ที่เรียกว่า$Bootมีอยู่แล้วในไดเรกทอรีหรือไม่
Christian Hayter

2

นี่เป็นคำถามที่ตอบแล้ว แต่เพื่อ "ตัวเลือกอื่น ๆ " นี่เป็นคำถามที่ไม่เหมาะ:

(ไม่เหมาะเนื่องจากใช้การยกเว้นเป็นตัวควบคุมการไหลคือ "สิ่งที่ไม่ดี" โดยทั่วไป)

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

ตัวอย่างของคุณใช้ไม่ได้กับไฟล์ CON (C: \ temp \ CON)
tcbrazil

แต่ไม่ใช่ 'C: \ temp \ CON' ชื่อไฟล์ที่ถูกต้องหรือไม่ ทำไมถึงไม่เป็นเช่นนั้น?
Mark A. Donohoe

@MarqueIV - ไม่มันไม่ถูกต้อง อ่านคำตอบและความคิดเห็นทั้งหมดข้างต้นหรือลองด้วยตัวคุณเองและดู
rory.ap

@Jer, "/ example" ไม่ถูกกฎหมาย แต่วิธีการของคุณจะกลับtrueมา
rory.ap

อ่าาาาา ... ฉันพลาดส่วน 'CON' ชื่อตัวเองนั้นถูกต้องจากจุดยืนสตริง (ซึ่งเป็นสิ่งที่ฉันหมายถึง) แต่ฉันเห็นตอนนี้ CON เป็นชื่อที่สงวนไว้ทำให้ไม่สามารถใช้งานได้จากมุมมองของ Windows ความผิดฉันเอง.
Mark A. Donohoe

2

นิพจน์ทั่วไปเกินความจำเป็นสำหรับสถานการณ์นี้ คุณสามารถใช้String.IndexOfAny()วิธีร่วมกับPath.GetInvalidPathChars()และPath.GetInvalidFileNameChars()และ

โปรดทราบว่าทั้งสองPath.GetInvalidXXX()วิธีจะโคลนอาร์เรย์ภายในและส่งคืนโคลน ดังนั้นหากคุณกำลังทำสิ่งนี้มาก (หลายพันครั้ง) คุณสามารถแคชสำเนาของอาร์เรย์ chars ที่ไม่ถูกต้องเพื่อนำมาใช้ซ้ำ


2

หากคุณเพียงแค่พยายามตรวจสอบว่าสตริงที่ถือชื่อไฟล์ / พา ธ ของคุณมีอักขระที่ไม่ถูกต้องหรือไม่วิธีที่เร็วที่สุดที่ฉันพบคือใช้Split()เพื่อแยกชื่อไฟล์ออกเป็นหลายส่วนในทุกที่ที่มีอักขระที่ไม่ถูกต้อง หากผลลัพธ์เป็นเพียงอาร์เรย์ 1 จะไม่มีอักขระที่ไม่ถูกต้อง :-)

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;

ฉันลองใช้วิธีนี้และวิธีการอื่น ๆ ที่กล่าวถึงข้างต้นในชื่อไฟล์ / เส้นทาง 1,000,000 ครั้งใน LinqPad

ใช้Split()เพียง ~ 850ms

ใช้Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")ประมาณ 6 วินาที

นิพจน์ทั่วไปที่ซับซ้อนยิ่งขึ้นนั้นแย่กว่าเดิมมากเช่นเดียวกับตัวเลือกอื่น ๆ เช่นการใช้วิธีการต่าง ๆ ในPathชั้นเรียนเพื่อรับชื่อไฟล์และให้การตรวจสอบภายในของพวกเขาทำงานได้ดีที่สุด

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


1

คำตอบเหล่านี้จำนวนมากจะไม่ทำงานหากชื่อไฟล์ยาวเกินไป & ทำงานบนสภาพแวดล้อม Windows 10 ก่อน ในทำนองเดียวกันให้คิดถึงสิ่งที่คุณต้องการทำกับจุด - อนุญาตให้นำหน้าหรือต่อท้ายมีความถูกต้องทางเทคนิค แต่สามารถสร้างปัญหาได้หากคุณไม่ต้องการให้ไฟล์ดูหรือลบได้ยากตามลำดับ

นี่เป็นคุณสมบัติการตรวจสอบความถูกต้องที่ฉันสร้างขึ้นเพื่อตรวจสอบชื่อไฟล์ที่ถูกต้อง

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

และการทดสอบ

[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

ความพยายามของฉัน:

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

สิ่งนี้ไม่สมบูรณ์เนื่องจากPath.GetInvalidPathCharsไม่ส่งคืนชุดอักขระทั้งหมดที่ไม่ถูกต้องในชื่อไฟล์และไดเรกทอรีและแน่นอนว่ามีรายละเอียดปลีกย่อยมากมาย

ดังนั้นฉันใช้วิธีนี้เป็นส่วนประกอบ:

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

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

คุณยังสามารถใช้วิธีแรกในการตรวจสอบความถูกต้องเบื้องต้นจากนั้นจัดการข้อยกเว้นอย่างรอบคอบเมื่อใช้พา ธ


0

ฉันขอแนะนำให้ใช้ Path.GetFullPath ()

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

เพิ่มคำอธิบายพร้อมคำตอบสำหรับวิธีที่คำตอบนี้ช่วย OP ในการแก้ไขปัญหาปัจจุบัน
Kяσѕρєя K

ดูเอกสารใน MSDN สำหรับ AugumentExcpetion ซึ่งอ่าน: path เป็นสตริงที่มีความยาวเป็นศูนย์มีเฉพาะพื้นที่สีขาวหรือมีอักขระที่ไม่ถูกต้องที่กำหนดไว้ใน GetInvalidPathChars อย่างน้อยหนึ่งตัว - หรือ - ระบบไม่สามารถเรียกคืนพา ธ สัมบูรณ์
โทนี่ซัน

ในทางทฤษฎี (ตามเอกสาร) สิ่งนี้ควรใช้งานได้ปัญหาอย่างน้อยที่สุดก็ใน. NET Core 3.1 แต่ก็ไม่ได้
Michel Jansson

0

ฉันได้รับความคิดนี้จากใครบางคน - ไม่รู้ว่าใคร ให้ระบบปฏิบัติการทำการยกของหนัก

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

ตรวจสอบนี้

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

ฟิลเตอร์ออกชื่อที่มีตัวอักษรที่ไม่ถูกต้อง ( <>:"/\|?*และ ASCII 0-31) รวมถึงอุปกรณ์ DOS ลิขสิทธิ์ ( CON, NUL, COMx) Path.GetFullPathจะช่วยให้ช่องว่างนำและทุกจุดชื่อให้สอดคล้องกับ (การสร้างไฟล์ด้วยช่องว่างนำประสบความสำเร็จในระบบของฉัน)


ใช้. NET Framework 4.7.1 ทดสอบบน Windows 7


0

หนึ่งซับสำหรับการตรวจสอบตัวอักษรลวงตาในสตริง:

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

0

ในความคิดของฉันคำตอบที่ถูกต้องสำหรับคำถามนี้คือพยายามใช้พา ธ และให้ระบบปฏิบัติการและระบบไฟล์ตรวจสอบความถูกต้อง มิฉะนั้นคุณจะเพิ่งนำมาใช้ใหม่ (และอาจไม่ดี) กฎการตรวจสอบทั้งหมดที่ระบบปฏิบัติการและระบบไฟล์ใช้อยู่แล้วและหากกฎเหล่านั้นมีการเปลี่ยนแปลงในอนาคตคุณจะต้องเปลี่ยนรหัสเพื่อให้ตรงกับกฎเหล่านั้น


-1

ชื่อไฟล์ Windows เป็น unrestrictive สวยดังนั้นจริงๆมันอาจจะไม่ได้เป็นที่มากของปัญหา อักขระที่ Windows ไม่อนุญาต ได้แก่ :

\ / : * ? " < > |

คุณสามารถเขียนนิพจน์เพื่อตรวจสอบว่ามีอักขระเหล่านั้นอยู่หรือไม่ ทางออกที่ดีกว่าคือการพยายามตั้งชื่อไฟล์ตามที่ผู้ใช้ต้องการและเตือนพวกเขาเมื่อชื่อไฟล์ไม่ติด


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