Bagaimana cara saya memeriksa apakah string yang diberikan adalah nama file yang sah / sah pada Windows?

165

Saya ingin memasukkan fungsi mengubah nama file batch dalam aplikasi saya. Seorang pengguna dapat mengetikkan pola nama tujuan dan (setelah mengganti beberapa wildcard dalam pola) Saya perlu memeriksa apakah itu akan menjadi nama file yang sah di Windows. Saya sudah mencoba menggunakan ekspresi reguler seperti [a-zA-Z0-9_]+tetapi tidak menyertakan banyak karakter khusus nasional dari berbagai bahasa (mis. Umlauts dan sebagainya). Apa cara terbaik untuk melakukan pemeriksaan seperti itu?

Tomash
sumber
Saya sarankan menggunakan Regex terkompilasi statis jika Anda akan menggunakan salah satu jawaban dengan Regex ..
AMissico

Jawaban:

100

Anda bisa mendapatkan daftar karakter yang tidak valid dari Path.GetInvalidPathCharsdan GetInvalidFileNameChars.

UPD: Lihat saran Steve Cooper tentang cara menggunakannya dalam ekspresi reguler.

UPD2: Perhatikan bahwa menurut bagian Catatan di MSDN "Array yang dikembalikan dari metode ini tidak dijamin mengandung set karakter lengkap yang tidak valid dalam nama file dan direktori." Jawaban yang diberikan oleh sixlettervaliables masuk ke rincian lebih lanjut.

Eugene Katz
sumber
11
Ini tidak menjawab pertanyaan; ada banyak string yang hanya terdiri dari karakter yang valid (mis. "....", "CON", string ratusan karakter) yang bukan nama file yang valid.
Dour High Arch
31
Adakah yang kecewa karena MS tidak menyediakan fungsi level sistem / API untuk kemampuan ini alih-alih setiap pengembang harus memasak solusinya sendiri? Ingin tahu apakah ada alasan yang sangat baik untuk ini atau hanya kekhilafan pada bagian MS.
Thomas Nguyen
@ Arch Tinggi: Lihat jawaban untuk pertanyaan "Di C # periksa bahwa nama file mungkin valid (tidak ada)". (Meskipun beberapa orang pintar menutup pertanyaan yang mendukung yang ini ...)
mmmmmmmm
129

Dari "Penamaan File atau Direktori" MSDN, berikut adalah konvensi umum untuk nama file hukum apa di bawah Windows:

Anda dapat menggunakan karakter apa pun di halaman kode saat ini (Unicode / ANSI di atas 127), kecuali:

  • < > : " / \ | ? *
  • Karakter yang representasi bilangan bulatnya adalah 0-31 (kurang dari ruang ASCII)
  • Karakter lain apa pun yang tidak diizinkan oleh sistem file target (katakanlah, trailing period atau spasi)
  • Nama DOS: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT7, LPT7, LPT8, LPT9 (dan hindari AUX.txt, dll)
  • Nama file adalah semua periode

Beberapa hal opsional untuk diperiksa:

  • Jalur file (termasuk nama file) mungkin tidak memiliki lebih dari 260 karakter (yang tidak menggunakan \?\awalan)
  • Jalur file Unicode (termasuk nama file) dengan lebih dari 32.000 karakter saat menggunakan \?\(perhatikan bahwa awalan dapat memperluas komponen direktori dan menyebabkannya melebihi batas 32.000)
pengguna7116
sumber
8
+1 untuk menyertakan nama file yang dipesan - yang terlewatkan dalam jawaban sebelumnya.
SqlRyan
2
"AUX" adalah nama file yang bisa digunakan jika Anda menggunakan sintaks "\\? \". Tentu saja, program yang tidak menggunakan sintaks yang memiliki masalah nyata berurusan dengan itu ... (Diuji pada XP)
user9876
9
Regex yang benar untuk semua kondisi yang disebutkan di atas adalah sebagai berikut:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
whywhywhy
4
@whywhywhy saya pikir Anda punya braket pembuka tambahan di Regex itu. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\. +) $) (\\ .. *)? $) | (([\\ \\ x00 - \\ x1f \\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" bekerja untuk saya.
Wilky
4
Saya membaca artikel yang sama yang disebutkan dalam jawaban ini dan menemukan melalui eksperimen bahwa COM0 dan LPT0 juga tidak diperbolehkan. @ dlf yang ini berfungsi dengan nama file yang dimulai dengan '.':^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr
67

Untuk .Net Frameworks sebelum 3.5 ini seharusnya berfungsi:

Pencocokan ekspresi reguler akan membantu Anda. Berikut cuplikan menggunakan System.IO.Path.InvalidPathCharskonstanta;

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

Untuk .Net Frameworks setelah 3.0 ini seharusnya berfungsi:

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

Pencocokan ekspresi reguler akan membantu Anda. Berikut cuplikan menggunakan System.IO.Path.GetInvalidPathChars()konstanta;

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

Setelah Anda tahu itu, Anda juga harus memeriksa format yang berbeda, misalnya c:\my\drivedan\\server\share\dir\file.ext

Steve Cooper
sumber
bukankah ini hanya menguji jalan, bukan nama file?
Eugene Katz
30
string strTheseAreInvalidFileNameChars = string baru (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = Regex baru ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
rao
2
Sebuah penelitian kecil dari orang akan menghasilkan keajaiban. Saya telah memperbarui pos untuk mencerminkan perubahan.
Erik Philips
1
Potongan kode kedua tidak dikompilasi. "Tidak dapat mengonversi dari char [] ke string
Paul Hunt
1
@AshkanMobayenKhiabani: InvalidPathChars sudah usang tetapi GetInvalidPathChars tidak.
IvanH
25

Cobalah untuk menggunakannya, dan jebak kesalahannya. Perangkat yang diizinkan dapat berubah di seluruh sistem file, atau di berbagai versi Windows. Dengan kata lain, jika Anda ingin tahu apakah Windows menyukai namanya, berikan nama itu dan beri tahu.


sumber
1
Ini tampaknya menjadi satu-satunya yang menguji terhadap semua kendala. Mengapa jawaban lain dipilih karena ini?
gap
5
@ gap karena tidak selalu berhasil. Misalnya, mencoba mengakses CON akan sering berhasil, meskipun itu bukan file nyata.
Antimony
4
Itu selalu lebih baik untuk menghindari overhead memori melempar Pengecualian, jika memungkinkan.
Owen Blacker
2
Selain itu, Anda mungkin tidak memiliki izin untuk mengaksesnya; misalnya untuk mengujinya dengan menulis, bahkan jika Anda dapat membacanya jika itu ada atau akan ada.
CodeLurker
23

Kelas ini membersihkan nama file dan jalur; gunakan seperti

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

Ini kodenya;

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

}
Steve Cooper
sumber
1
jawaban Anda bisa lebih cocok di sini: stackoverflow.com/questions/146134/…
nawfal
22

Inilah yang saya gunakan:

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

Pola pertama membuat ekspresi reguler yang berisi nama file dan karakter yang tidak valid / ilegal hanya untuk platform Windows. Yang kedua melakukan hal yang sama tetapi memastikan bahwa nama tersebut legal untuk platform apa pun.

Scott Dorman
sumber
4
sPattern regex tidak mengizinkan file dimulai dengan karakter titik. Tetapi MSDN mengatakan "dapat diterima untuk menentukan periode sebagai karakter pertama dari sebuah nama. Misalnya," .temp "". Saya akan menghapus "\ .. *" untuk membuat .gitignore nama file yang benar :)
yar_shukan
(Saya telah secara bertahap membuat ini lebih baik dan menghapus komentar sebelumnya yang saya tinggalkan) Yang ini lebih baik daripada regex jawaban karena memungkinkan ".gitignore", "..asdf", tidak mengizinkan '<' dan '>' atau yen tandatangani, dan tidak mengizinkan ruang atau titik di bagian akhir (yang tidak mengizinkan nama yang hanya terdiri dari titik-titik):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr
ini gagal untuk semua file yang saya uji. menjalankannya untuk C: \ Windows \ System32 \ msxml6.dll laporan palsu.
magicandre1981
@ magicandre1981 Anda harus memberikan hanya nama file, bukan jalur yang sepenuhnya memenuhi syarat.
Scott Dorman
ok, tapi saya perlu memeriksa apakah path lengkap valid. Sekarang saya menggunakan solusi yang berbeda.
magicandre1981
18

Satu hal yang perlu diingat, yang mengejutkan saya ketika saya pertama kali mengetahuinya: Windows memungkinkan karakter ruang terkemuka dalam nama file! Misalnya, berikut ini semua nama file yang sah dan berbeda pada Windows (minus tanda kutip):

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

Satu hal yang bisa diambil dari ini: Berhati-hatilah saat menulis kode yang memotong spasi spasi awal / akhir dari string nama file.

Jon Schneider
sumber
10

Menyederhanakan jawaban Eugene Katz:

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

Atau

bool IsFileNameCorrect(string fileName){
    return fileName.All(f=>!Path.GetInvalidFileNameChars().Contains(f))
}
tmt
sumber
Apakah maksud Anda: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Berisi (f));" ?
Jack Griffin
@JackGriffin Tentu saja! Terima kasih atas perhatiannya.
tmt
Meskipun kode ini sangat bagus untuk dibaca, kita harus memperhitungkan internal maaf Path.GetInvalidFileNameChars. Lihatlah di sini: Referenceource.microsoft.com/#mscorlib/system/io/path.cs,299 - untuk setiap karakter Anda fileName, klon dari array dibuat.
Piotr Zierhoffer
"DD: AAA ..... AAAA". Tidak valid, tetapi untuk kode Anda, itu benar.
Ciccio Pasticcio
8

Microsoft Windows: Kernel Windows melarang penggunaan karakter dalam rentang 1-31 (yaitu, 0x01-0x1F) dan karakter "*: <>? \ |. Meskipun NTFS memungkinkan setiap komponen jalur (direktori atau nama file) panjangnya 255 karakter dan panjang jalur hingga sekitar 32.767 karakter, kernel Windows hanya mendukung jalur hingga 259 karakter. Selain itu, Windows melarang penggunaan nama perangkat MS-DOS AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL dan PRN, serta nama-nama ini dengan ekstensi apa pun (misalnya, AUX.txt), kecuali saat menggunakan Lintasan UNC panjang (mis. \. \ C: \ nul.txt atau \? \ D: \ aux \ con). (Faktanya, CLOCK $ dapat digunakan jika ekstensi diberikan.) Pembatasan ini hanya berlaku untuk Windows - Linux, misalnya, memungkinkan penggunaan "*: <>? \ | bahkan dalam NTFS.

Sumber: http://en.wikipedia.org/wiki/Filename

Martin Faartoft
sumber
1
Saya dapat membuat file bernama "CLOCK $" baik-baik saja. Windows 7.
rory.ap
7

Daripada secara eksplisit memasukkan semua karakter yang mungkin, Anda bisa melakukan regex untuk memeriksa keberadaan karakter ilegal, dan melaporkan kesalahan saat itu. Idealnya aplikasi Anda harus memberi nama file persis seperti yang diinginkan pengguna, dan hanya menangis busuk jika menemukan kesalahan.

ConroyP
sumber
6

Pertanyaannya adalah apakah Anda mencoba menentukan apakah nama jalur adalah jalur jendela yang sah, atau apakah itu sah pada sistem tempat kode tersebut berjalan.? Saya pikir yang terakhir lebih penting, jadi secara pribadi, saya mungkin akan menguraikan path lengkap dan mencoba menggunakan _mkdir untuk membuat direktori milik file, kemudian mencoba untuk membuat file.

Dengan cara ini Anda tahu tidak hanya jika path hanya berisi karakter windows yang valid, tetapi jika itu benar-benar mewakili path yang dapat ditulis oleh proses ini.

kfh
sumber
6

Saya menggunakan ini untuk menyingkirkan karakter yang tidak valid dalam nama file tanpa memberikan pengecualian:

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

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

Juga CON, PRN, AUX, NUL, COM # dan beberapa lainnya tidak pernah nama file hukum dalam direktori apa pun dengan ekstensi apa pun.


sumber
1
Ini hanya setengah dari kebenaran. Anda dapat membuat file dengan nama-nama ini jika memanggil versi unicode dari CreateFile (awalan nama file dengan "\\? \").
Werner Henze
Pernyataan ini tidak lengkap dan merindukan LPT #
Thomas Weller
4

Untuk melengkapi jawaban lain, berikut adalah beberapa kasus tepi tambahan yang mungkin ingin Anda pertimbangkan.

Joe
sumber
3

Dari MSDN , berikut daftar karakter yang tidak diizinkan:

Gunakan hampir semua karakter di halaman kode saat ini untuk sebuah nama, termasuk karakter Unicode dan karakter dalam set karakter yang diperluas (128–255), kecuali untuk yang berikut:

  • Karakter yang dipesan berikut ini tidak diizinkan: <>: "/ \ |? *
  • Karakter yang representasi bilangan bulatnya berkisar dari nol hingga 31 tidak diizinkan.
  • Karakter lain apa pun yang tidak diizinkan oleh sistem file target.
Mark Biek
sumber
2

Sistem file tujuan juga penting.

Di bawah NTFS, beberapa file tidak dapat dibuat di direktori tertentu. EG $ Boot di root

Dominik Weber
sumber
2
Tentunya itu bukan karena aturan penamaan NTFS, tetapi hanya karena file yang dipanggil $Bootsudah ada di direktori?
Christian Hayter
2

Ini adalah pertanyaan yang sudah dijawab, tetapi hanya demi "Pilihan lain", berikut ini adalah pertanyaan yang tidak ideal:

(tidak ideal karena menggunakan Pengecualian sebagai kontrol aliran adalah "Hal Buruk", umumnya)

public static bool IsLegalFilename(string name)
{
    try 
    {
        var fileInfo = new FileInfo(name);
        return true;
    }
    catch
    {
        return false;
    }
}
Jerimbimball
sumber
Contoh Anda tidak berfungsi untuk file CON (C: \ temp \ CON).
tcbrazil
Tetapi bukankah 'C: \ temp \ CON' nama file yang valid? Kenapa tidak?
Mark A. Donohoe
@MarqueIV - tidak, ini tidak valid. Baca semua jawaban dan komentar di atas, atau coba sendiri dan lihat.
rory.ap
@ Jer, "/ example" tidak sah, namun metode Anda kembali true.
rory.ap
Aaaah ... Aku merindukan bagian 'CON'. Nama itu sendiri valid dari sudut pandang string (yang saya maksudkan), tetapi saya melihat sekarang CON adalah nama yang dilindungi undang-undang, menjadikannya tidak valid dari sudut pandang Windows. Salahku.
Mark A. Donohoe
2

Ekspresi reguler berlebihan untuk situasi ini. Anda dapat menggunakan String.IndexOfAny()metode ini dalam kombinasi dengan Path.GetInvalidPathChars()dan Path.GetInvalidFileNameChars().

Perhatikan juga bahwa kedua Path.GetInvalidXXX()metode mengkloning array internal dan mengembalikan clone. Jadi, jika Anda akan sering melakukan ini (ribuan dan ribuan kali), Anda dapat menyimpan salinan array chars array yang tidak valid untuk digunakan kembali.

nhahtdh
sumber
2

Jika Anda hanya mencoba memeriksa apakah string yang menyimpan nama / jalur file Anda memiliki karakter yang tidak valid, metode tercepat yang saya temukan adalah menggunakan Split()untuk memecah nama file menjadi array bagian di mana pun ada karakter yang tidak valid. Jika hasilnya hanya array 1, tidak ada karakter yang tidak valid. :-)

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;

Saya mencoba menjalankan ini dan metode lain yang disebutkan di atas pada nama file / path 1.000.000 kali di LinqPad.

Menggunakan Split()hanya ~ 850ms.

Penggunaannya Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")sekitar 6 detik.

Ekspresi reguler yang lebih rumit jauh lebih buruk, seperti halnya beberapa opsi lain, seperti menggunakan berbagai metode di Pathkelas untuk mendapatkan nama file dan membiarkan validasi internal mereka melakukan pekerjaan (kemungkinan besar karena overhead penanganan pengecualian).

Memang tidak terlalu sering Anda perlu memvalidasi 1 juta nama file, jadi iterasi tunggal tidak masalah untuk sebagian besar metode ini. Tapi itu masih cukup efisien dan efektif jika Anda hanya mencari karakter yang tidak valid.

Nick Albrecht
sumber
1

banyak dari jawaban ini tidak akan berfungsi jika nama file terlalu panjang & berjalan di lingkungan pra Windows 10. Demikian pula, pikirkan tentang apa yang ingin Anda lakukan dengan titik - memungkinkan memimpin atau mengekor secara teknis valid, tetapi dapat membuat masalah jika Anda tidak ingin file menjadi sulit dilihat atau dihapus masing-masing.

Ini adalah atribut validasi yang saya buat untuk memeriksa nama file yang valid.

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

dan tes

[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"));
}
Brent
sumber
1

Usaha saya:

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

Ini tidak sempurna karena Path.GetInvalidPathCharstidak mengembalikan set karakter lengkap yang tidak valid dalam nama file dan direktori dan tentu saja ada banyak lagi kehalusan.

Jadi saya menggunakan metode ini sebagai pelengkap:

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

Mencoba membuat file dan mengembalikan false jika ada pengecualian. Tentu saja, saya perlu membuat file tetapi saya pikir itu cara paling aman untuk melakukannya. Harap perhatikan juga bahwa saya tidak menghapus direktori yang telah dibuat.

Anda juga dapat menggunakan metode pertama untuk melakukan validasi dasar, dan kemudian menangani dengan hati-hati pengecualian saat jalur digunakan.

Maxence
sumber
0

Saya sarankan gunakan saja Path.GetFullPath ()

string tagetFileFullNameToBeChecked;
try
{
  Path.GetFullPath(tagetFileFullNameToBeChecked)
}
catch(AugumentException ex)
{
  // invalid chars found
}
Tony Sun
sumber
Tambahkan beberapa penjelasan dengan jawaban untuk bagaimana jawaban ini membantu OP dalam memperbaiki masalah saat ini
ρяσѕρєя K
Lihat dokumen di MSDN untuk AugumentExcpetion, terbaca: path adalah string dengan panjang nol, hanya berisi spasi putih, atau berisi satu atau lebih karakter tidak valid yang ditentukan dalam GetInvalidPathChars. -atau- Sistem tidak dapat mengambil jalur absolut.
Tony Sun
Dalam teori (menurut dokumen) ini harus bekerja, masalahnya adalah setidaknya dalam. NET Core 3.1, tidak.
Michel Jansson
0

Saya mendapat ide ini dari seseorang. - tidak tahu siapa. Biarkan OS melakukan angkat berat.

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;
}
Ken
sumber
0

Cek ini

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

filter nama-nama dengan karakter yang tidak valid ( <>:"/\|?*dan ASCII 0-31), serta perangkat DOS dilindungi ( CON, NUL, COMx). Ini memungkinkan spasi dan semua nama titik terkemuka, konsisten dengan Path.GetFullPath. (Membuat file dengan spasi terdepan berhasil di sistem saya).


Digunakan .NET Framework 4.7.1, diuji pada Windows 7.

Vlad
sumber
0

Satu liner untuk memverifikasi karakter ilegal di string:

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

Menurut pendapat saya, satu-satunya jawaban yang tepat untuk pertanyaan ini adalah mencoba menggunakan path dan membiarkan OS dan sistem file memvalidasinya. Kalau tidak, Anda hanya mengimplementasikan ulang (dan mungkin buruk) semua aturan validasi yang sudah digunakan OS dan sistem file dan jika aturan itu diubah di masa depan Anda harus mengubah kode Anda agar cocok dengan mereka.

Igor Levicki
sumber
-1

Jendela nama file cukup unrestrictive, sehingga benar-benar bahkan tidak mungkin bahwa banyak masalah. Karakter yang dilarang oleh Windows adalah:

\ / : * ? " < > |

Anda dapat dengan mudah menulis ekspresi untuk memeriksa apakah karakter tersebut ada. Solusi yang lebih baik adalah dengan mencoba dan memberi nama file sesuai keinginan pengguna, dan mengingatkan mereka ketika nama file tidak menempel.

Justin Poliey
sumber
Juga karakter <= 31 dilarang.
Antimony