Belirli bir dizenin Windows altında yasal / geçerli bir dosya adı olup olmadığını nasıl kontrol edebilirim?


165

Uygulamama bir toplu iş dosyası yeniden adlandırma işlevi eklemek istiyorum. Bir kullanıcı bir hedef dosya adı deseni yazabilir ve (desendeki bazı joker karakterleri değiştirdikten sonra) Windows altında yasal bir dosya adı olup olmayacağını kontrol etmem gerekir. Gibi düzenli ifade kullanmaya çalıştım [a-zA-Z0-9_]+ama çeşitli dillerden (örneğin, umlauts ve benzeri) birçok ulusal özgü karakter içermiyor. Böyle bir çek yapmanın en iyi yolu nedir?


Eğer herhangi bir cevap Regex ile kullanacaksanız statik bir derlenmiş Regex kullanmanızı öneririz ..
AMissico

Yanıtlar:


100

Sen geçersiz karakterlerin bir listesini alabilirsiniz Path.GetInvalidPathCharsve GetInvalidFileNameChars.

UPD: Steve Cooper'ın bunları düzenli bir ifadede nasıl kullanacağına dair önerisine bakın .

UPD2: MSDN'deki Açıklamalar bölümüne göre "Bu yöntemden döndürülen dizinin, dosya ve dizin adlarında geçersiz olan tüm karakter kümesini içereceği garanti edilmez." Altı farklılıklar tarafından verilen cevap daha fazla ayrıntıya girer.


11
Bu soruya cevap vermez; geçerli dosya adları olmayan yalnızca geçerli karakterlerden (örneğin "....", "CON", yüzlerce karakter uzunluğundaki dizelerden) oluşan birçok dize vardır.
Dour Yüksek Arch

31
Herkes, MS'in her bir geliştiricinin kendi çözümünü pişirmesi yerine bu yetenek için sistem düzeyinde işlev / API sağlamadığını hayal kırıklığına uğratır mı? Bunun çok iyi bir nedeni mi yoksa sadece MS bölümünde bir gözetim olup olmadığını merak ediyorum.
Thomas Nguyen

@Yüksek Kemer: "C # 'da dosya adının muhtemelen geçerli olup olmadığını kontrol edin (mevcut değil) sorusunun cevabına bakın . (Bazı zeki çocuklar bu soruyu lehine kapatmış olsalar da ...)
mmmmmmmm

129

Gönderen MSDN'ın "adlandırma bir dosya veya Directory," Burada yasal bir dosya adı Windows altında ne için genel kurallar şunlardır:

Şu anki kod sayfasında (Unicode / ANSI, 127'nin üzerinde) herhangi bir karakter kullanabilirsiniz, ancak aşağıdakiler hariç:

  • < > : " / \ | ? *
  • Tamsayı gösterimleri 0-31 (ASCII uzayından daha az) olan karakterler
  • Hedef dosya sisteminin izin vermediği diğer karakterler (örneğin, sondaki dönemler veya boşluklar)
  • DOS adlarından herhangi biri: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 (ve AUX.txt, vb. Önlemek)
  • Dosya adı tüm dönemler

Kontrol etmek için isteğe bağlı bazı şeyler:

  • Dosya yollarında (dosya adı dahil) 260 karakterden fazla olamaz ( \?\önek kullanılmaz)
  • Kullanırken 32.000'den fazla karakter içeren Unicode dosya yolları (dosya adı dahil) \?\(önekin dizin bileşenlerini genişletebileceğini ve 32.000 sınırını aşmasına neden olabileceğini unutmayın)

8
Ayrılmış dosya adlarını dahil etmek için +1 - önceki yanıtlarda kaçırılanlar.
SqlRyan

2
"\\? \" Sözdizimini kullanırsanız, "AUX" mükemmel kullanılabilir bir dosya adıdır. Tabii ki, bu sözdizimini kullanmayan programların
kendisiyle

9
Yukarıda belirtilen tüm bu koşullar için doğru normal ifade aşağıdaki gibidir:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
neden

4
@neden neden bu Regex'te fazladan bir açılış paranız olduğunu düşünüyorum. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\ +) $) (\\ .. *) $.?) | (([\\ x00 - \\ x1f \\\\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" benim için çalıştı.
Wilky

4
Bu cevapta belirtilen makaleyi okudum ve deneyler yoluyla COM0 ve LPT0'a da izin verilmediğini buldum. @dlf bu '.' ile başlayan dosya adlarıyla çalışır:^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr

67

For .Net Çerçeveleri öncesinde 3,5'e bu çalışması gerekir:

Düzenli ifade eşlemesi size yol göstermelidir. İşte System.IO.Path.InvalidPathCharssabiti kullanan bir pasaj ;

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

For .Net Çerçeveleri 3.0 sonra bu çalışması gerekir:

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

Düzenli ifade eşlemesi size yol göstermelidir. İşte System.IO.Path.GetInvalidPathChars()sabiti kullanan bir pasaj ;

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

Bunu öğrendiğinizde, aynı zamanda farklı biçimleri, örneğin kontrol etsinler c:\my\driveve\\server\share\dir\file.ext


bu sadece yolu test etmiyor, dosya adını değil?
Eugene Katz

30
string strTheseAreInvalidFileNameChars = yeni dize (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = new Regex ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
rao

2
İnsanlardan yapılan küçük bir araştırma harikalar yaratacaktı. Yayını, değişiklikleri yansıtacak şekilde güncelledim.
Erik Philips

1
2. kod parçası derlenmez. "Char [] 'den dizeye dönüştürülemiyor
Paul Hunt

1
@AshkanMobayenKhiabani: InvalidPathChars kullanılmıyor, ancak GetInvalidPathChars çalışmıyor.
IvanH

25

Kullanmayı deneyin ve hatayı yakalayın. İzin verilen küme, dosya sistemlerinde veya Windows'un farklı sürümlerinde değişebilir. Diğer bir deyişle, Windows'un adı beğenip beğenmediğini bilmek istiyorsanız, adı verin ve size söylesin.


1
Bu, tüm kısıtlamalara karşı test eden tek kişi gibi görünüyor. Diğer cevaplar neden bu konuda seçiliyor?
boşluk

5
@gap çünkü her zaman çalışmaz. Örneğin, gerçek bir dosya olmasa da, CON'a erişmeye çalışmak genellikle başarılı olur.
Antimon

4
Bununla birlikte, mümkünse, bir İstisna atmanın bellek yükünü önlemek her zaman daha iyidir.
Owen Blacker

2
Ayrıca, erişim izniniz olmayabilir; örneğin, yazarak test etmek, eğer varsa ya da olacaksa okuyabilirsiniz.
CodeLurker

23

Bu sınıf dosya adlarını ve yolları temizler; gibi kullan

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

İşte kod;

/// <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
cevabınız buraya daha uygun olabilir: stackoverflow.com/questions/146134/…
nawfal

22

Ne kullanıyorum:

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

İlk kalıp, yalnızca Windows platformları için geçersiz / geçersiz dosya adlarını ve karakterlerini içeren normal bir ifade oluşturur. İkincisi de aynısını yapar, ancak adın herhangi bir platform için yasal olmasını sağlar.


4
sPattern regex, nokta karakteriyle başlayan dosyalara izin vermez. Ancak MSDN, "adın ilk karakteri olarak nokta belirtmek kabul edilebilir. Örneğin," .temp "" diyor. .Gitignore doğru dosya adını yapmak için "\ .. *" kaldıracağım :)
yar_shukan

(Bunu kademeli olarak daha iyi yaptım ve bıraktığım önceki yorumları sildim) Bu yanıt, ".gitignore", "..asdf", '<' ve '>' veya yen'e izin vermediği için yanıtın normal ifadesinden daha iyidir işareti, ve sonunda boşluk veya süre izin vermez (sadece noktalardan oluşan isimlere izin vermez):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr

test ettiğim tüm dosyalar için bu başarısız olur. C: \ Windows \ System32 \ msxml6.dll için çalıştırıldığında hata bildirilir.
magicandre1981

@ magicandre1981 Tam yol değil, sadece dosya adını vermeniz gerekir.
Scott Dorman

Tamam, ama tam yolun geçerli olup olmadığını kontrol etmem gerekiyor. Şimdi farklı bir çözüm kullandım.
magicandre1981

18

Akılda tutulması gereken bir köşe örneği, ilk öğrendiğimde beni şaşırttı: Windows dosya adlarında önde gelen boşluk karakterlerine izin veriyor! Örneğin, aşağıdakilerin tümü Windows'daki yasal ve farklı dosya adlarıdır (tırnak işaretleri eksi):

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

Bundan bir paket: Bir dosya adı dizesinden baştaki / sondaki boşluğu kesen kod yazarken dikkatli olun.


10

Eugene Katz'ın cevabını basitleştirmek:

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

Veya

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

Şunu mu demek istediniz: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Contains (f));" ?
Jack Griffin

@JackGriffin Elbette! Dikkatiniz için teşekkür ederim.
tmt

Bu kodu okumak çok güzel olsa da, özür dileriz Path.GetInvalidFileNameChars. Buraya bir göz atın: referenceource.microsoft.com/#mscorlib/system/io/path.cs,289 - her bir karakteriniz fileNameiçin dizinin bir kopyası oluşturulur.
Piotr Zierhoffer

"DD: \\\\\ AAA ..... AAAA". Geçerli değil, ancak kodunuz için geçerli.
Ciccio Pasticcio

8

Microsoft Windows: Windows çekirdeği 1-31 aralığındaki karakterlerin (ör. 0x01-0x1F) ve "*: <>? \ | Karakterlerinin kullanılmasını yasaklasa da, NTFS her yol bileşeninin (dizin veya dosya adı) 255 karakter uzunluğunda olmasına izin verir ve yaklaşık 32767 karakter uzunluğa kadar olan yollarda, Windows çekirdeği yalnızca 259 karakter uzunluğa kadar olan yolları destekler.Ayrıca, Windows, MS-DOS aygıt adlarının AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL ve PRN ve bunların dışında herhangi bir uzantıya sahip bu adlar (örneğin, AUX.txt) Uzun UNC yolları (ör. \. \ C: \ nul.txt veya \? \ D: \ aux \ con). (Aslında, bir uzantı sağlanmışsa CLOCK $ kullanılabilir.) Bu kısıtlamalar yalnızca Windows için geçerlidir - Örneğin Linux "*: <>? \ | NTFS'de bile.

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


1
"CLOCK $" adında bir dosya oluşturabilirim. Windows 7.
rory.ap

7

Tüm olası karakterleri açıkça eklemek yerine, yasadışı karakterlerin varlığını kontrol etmek ve ardından bir hata bildirmek için normal ifade yapabilirsiniz. İdeal olarak uygulamanız dosyaları tam olarak kullanıcının istediği şekilde adlandırmalı ve yalnızca bir hataya rastlarsa faul ağlamalıdır.


6

Soru, bir yol adının yasal bir pencere yolu olup olmadığını veya kodun çalıştığı sistemde yasal olup olmadığını belirlemeye çalışmaktır.? Ben ikincisinin daha önemli olduğunu düşünüyorum, bu yüzden kişisel olarak, muhtemelen tam yolu ayrıştırır ve dosyanın ait olduğu dizini oluşturmak için _mkdir kullanmaya çalışırım, sonra dosyayı oluşturmaya çalışırım.

Bu şekilde, yalnızca yolun yalnızca geçerli Windows karakterleri içerdiğini değil, bu işlem tarafından yazılabilecek bir yolu temsil ettiğini de bilirsiniz.


6

İstisnalar atmadan dosya adlarındaki geçersiz karakterlerden kurtulmak için bunu kullanıyorum:

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

Ayrıca CON, PRN, AUX, NUL, COM # ve birkaçı, hiçbir uzantıya sahip herhangi bir dizinde hiçbir zaman yasal dosya adı değildir.


1
Bu gerçeğin sadece yarısı. CreateFile'ın unicode sürümünü çağırıyorsanız (dosya adının önüne "\\? \" Eklenmişse) bu adlara sahip dosyalar oluşturabilirsiniz.
Werner Henze

Bu ifade eksik ve LPT # özlüyor
Thomas Weller

4

Diğer cevapları tamamlamak için, göz önünde bulundurmak isteyebileceğiniz birkaç ek durum var.


3

Gönderen MSDN , burada izin verilmeyen karakterlerin listesi aşağıda verilmiştir:

Unicode karakterler ve genişletilmiş karakter kümesindeki karakterler (128-255) dahil olmak üzere, geçerli kod sayfasındaki neredeyse tüm karakterleri, aşağıdakiler dışında kullanın:

  • Şu ayrılmış karakterlere izin verilmiyor: <>: "/ \ |? *
  • Tamsayı gösterimleri sıfır ile 31 arasında olan karakterlere izin verilmez.
  • Hedef dosya sisteminin izin vermediği diğer karakterler.

2

Hedef dosya sistemi de önemlidir.

NTFS altında, bazı dosyalar belirli dizinlerde oluşturulamaz. EG $ Kökte Önyükleme


2
Elbette bunun nedeni NTFS adlandırma kuralı değil, yalnızca $Bootdizinde zaten bir dosya bulunması nedeniyle mi?
Christian Hayter

2

Bu zaten cevaplanmış bir soru, ama sadece "Diğer seçenekler" uğruna, ideal olmayan bir soru:

(ideal değil çünkü istisnaları akış kontrolü olarak kullanmak genellikle bir "Kötü Şey" dir)

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

Örneğiniz bir CON dosyası (C: \ temp \ CON) için çalışmadı.
tcbrazil

Ancak 'C: \ temp \ CON' geçerli bir dosya adı değil mi? Neden olmasın?
Mark A. Donohoe

@MarqueIV - hayır, geçerli değil. Yukarıdaki tüm cevapları ve yorumları okuyun veya kendiniz deneyin ve görün.
rory.ap

@Jer, "/ example" yasal değil, ancak yönteminiz geri dönüyor true.
rory.ap

Aaaah ... 'CON' bölümünü kaçırdım. Adın kendisi bir dize bakış açısından geçerlidir (bu da atıfta bulunduğum şeydir), ancak şimdi CON'un ayrılmış bir ad olduğunu görüyorum, bu da Windows açısından geçerli olmadığını gösteriyor. Benim hatam.
Mark A. Donohoe

2

Bu durum için düzenli ifadeler aşırıya kaçıyor. Sen kullanabilirsiniz String.IndexOfAny()birlikte yöntemini Path.GetInvalidPathChars()vePath.GetInvalidFileNameChars() .

Ayrıca her iki Path.GetInvalidXXX()yöntemin bir dahili diziyi klonladığını ve klonu döndürdüğünü unutmayın . Yani bunu çok yapacaksanız (binlerce ve binlerce kez) geçersiz karakter dizisinin bir kopyasını yeniden kullanmak üzere önbelleğe alabilirsiniz.


2

Yalnızca dosya adınızı / yolunuzu tutan bir dizenin geçersiz karakterleri olup olmadığını kontrol etmeye çalışıyorsanız, bulduğum en hızlı yöntem Split(), dosya adını geçersiz bir karakterin olduğu yerlerde bir parça dizisine ayırmak için kullanmaktır . Sonuç yalnızca 1 diziyse, geçersiz karakter yoktur. :-)

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;

Bu ve LinqPad bir dosya / yol adı 1.000.000 kez yukarıda belirtilen diğer yöntemleri çalışmayı denedim.

Kullanmak Split()sadece ~ 850ms.

Kullanımı Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")yaklaşık 6 saniyedir.

Daha karmaşık düzenli ifadeler, Pathdosya adını almak ve dahili doğrulamalarının işi yapmasına izin vermek için sınıftaki çeşitli yöntemleri kullanmak gibi (diğer olasılıkla istisna işleme yükü nedeniyle) diğer seçeneklerin bazıları gibi, çok daha kötüdür .

1 milyon dosya adını doğrulamanız gerekmediği için, bu yöntemlerin çoğu için yine de tek bir yineleme iyidir. Ancak, yalnızca geçersiz karakterler arıyorsanız, yine de oldukça verimli ve etkilidir.


1

dosya adı çok uzunsa ve Windows 10 öncesi bir ortamda çalışıyorsa bu yanıtların çoğu çalışmaz. Benzer şekilde, noktalarla ne yapmak istediğiniz hakkında bir düşünün - liderlik veya izlemeye izin vermek teknik olarak geçerlidir, ancak dosyanın sırasıyla görülmesini veya silinmesini istemiyorsanız sorun oluşturabilir.

Bu, geçerli bir dosya adını kontrol etmek için oluşturduğum bir doğrulama özelliğidir.

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

ve testler

[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

Girişimim:

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

Bu mükemmel değildir, çünkü Path.GetInvalidPathCharsdosya ve dizin adlarında geçersiz olan tüm karakterleri döndürmez ve elbette çok daha fazla incelik vardır.

Bu yöntemi bir tamamlayıcı olarak kullanıyorum:

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

Bir istisna varsa dosyayı oluşturmaya ve false döndürmeye çalışır. Tabii ki, dosyayı oluşturmam gerekiyor ama bence bunu yapmanın en güvenli yolu. Ayrıca oluşturulan dizinleri silmediğimi de unutmayın.

Ayrıca, temel doğrulamayı yapmak için ilk yöntemi kullanabilir ve yol kullanıldığında özel durumları dikkatlice işleyebilirsiniz.


0

Ben sadece Path.GetFullPath () kullanmanızı öneririz

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

Bu cevabın mevcut sorunu
çözmede OP'ye

AugumentExcpetion için MSDN'deki dokümana bakın: yol sıfır uzunluklu bir dizedir, yalnızca beyaz boşluk içerir veya GetInvalidPathChars içinde tanımlanan bir veya daha fazla geçersiz karakter içerir. -VEYA- Sistem mutlak yolu alamadı.
Tony Sun

Teoride (belgelere göre) bu işe yaramalı, sorun en azından .NET Core 3.1'de değil, öyle değil.
Michel Jansson

0

Bu fikri birinden aldım. - kim olduğunu bilmiyorum. OS ağır kaldırma yapsın.

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

Bu çek

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

Geçersiz karakter (ile adlarıyla dışarı filtreler <>:"/\|?*ve ASCII 0-31), hem de saklıdır DOS cihazlar ( CON, NUL, COMx). Önde gelen boşluklara ve tüm nokta adlarına tutarlı olarak izin verir Path.GetFullPath. (Öncü boşluklarla dosya oluşturmak sistemimde başarılı olur).


Windows 7'de test edilen .NET Framework 4.7.1 kullanıldı.


0

Dizedeki illigal karakterlerini doğrulamak için bir astar:

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

0

Kanımca, bu sorunun tek doğru cevabı yolu kullanmaya çalışmak ve işletim sisteminin ve dosya sisteminin doğrulamasını sağlamaktır. Aksi takdirde, işletim sisteminin ve dosya sisteminin zaten kullandığı tüm doğrulama kurallarını yeniden uygularsınız (ve muhtemelen kötü bir şekilde) ve gelecekte bu kurallar değiştirilirse kodunuzu bunlarla eşleşecek şekilde değiştirmeniz gerekecektir.


-1

, Windows dosya adları böylece gerçekten bile olmayabilir, oldukça sınırlamaz olan bu pek bir sorun. Windows tarafından izin verilmeyen karakterler:

\ / : * ? " < > |

Bu karakterlerin mevcut olup olmadığını kontrol etmek için kolayca bir ifade yazabilirsiniz. Daha iyi bir çözüm, dosyaları kullanıcının istediği gibi adlandırmaya çalışmak ve bir dosya adı yapışmadığında onları uyarmak olacaktır.


Ayrıca <= 31 karakterleri de yasaktır.
Antimon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.