Wie überprüfe ich, ob eine bestimmte Zeichenfolge unter Windows ein gültiger / gültiger Dateiname ist?


165

Ich möchte eine Funktion zum Umbenennen von Batchdateien in meine Anwendung aufnehmen. Ein Benutzer kann ein Zieldateinamenmuster eingeben und (nachdem er einige Platzhalter im Muster ersetzt hat) muss ich überprüfen, ob es sich unter Windows um einen legalen Dateinamen handelt. Ich habe versucht, reguläre Ausdrücke wie zu verwenden, [a-zA-Z0-9_]+aber es enthält nicht viele nationalspezifische Zeichen aus verschiedenen Sprachen (z. B. Umlaute usw.). Was ist der beste Weg, um eine solche Überprüfung durchzuführen?


Ich schlage vor, einen statisch kompilierten Regex zu verwenden, wenn Sie eine der Antworten mit Regex verwenden
möchten

Antworten:


100

Sie können eine Liste ungültiger Zeichen von Path.GetInvalidPathCharsund erhalten GetInvalidFileNameChars.

UPD: Siehe Steve Coopers Vorschlag, wie man diese in einem regulären Ausdruck verwendet.

UPD2: Beachten Sie, dass gemäß dem Abschnitt "Bemerkungen" in MSDN "das von dieser Methode zurückgegebene Array nicht garantiert den vollständigen Satz von Zeichen enthält, die in Datei- und Verzeichnisnamen ungültig sind." Die Antwort von sixlettervaliables geht auf weitere Details ein.


11
Dies beantwortet die Frage nicht; Es gibt viele Zeichenfolgen, die nur aus gültigen Zeichen bestehen (z. B. "....", "CON", Zeichenfolgen mit einer Länge von Hunderten von Zeichen), die keine gültigen Dateinamen sind.
Dour High Arch

31
Hat noch jemand enttäuscht, dass MS keine Funktion / API auf Systemebene für diese Funktion bereitstellt, anstatt dass jeder Entwickler seine eigene Lösung kochen muss? Ich frage mich, ob es einen sehr guten Grund dafür gibt oder nur ein Versehen auf MS-Seite.
Thomas Nguyen

@High Arch: Siehe Antwort auf Frage "Überprüfen Sie in C #, ob der Dateiname möglicherweise gültig ist (nicht, dass er existiert)". (Obwohl einige kluge Kerle diese Frage zugunsten dieser geschlossen haben ...)
mmmmmmmm

129

In MSDNs "Benennen einer Datei oder eines Verzeichnisses" finden Sie hier die allgemeinen Konventionen für die Verwendung eines legalen Dateinamens unter Windows:

Sie können ein beliebiges Zeichen in der aktuellen Codepage verwenden (Unicode / ANSI über 127), außer:

  • < > : " / \ | ? *
  • Zeichen, deren ganzzahlige Darstellungen 0-31 sind (weniger als ASCII-Leerzeichen)
  • Alle anderen Zeichen, die das Zieldateisystem nicht zulässt (z. B. nachgestellte Punkte oder Leerzeichen)
  • Beliebiger DOS-Name: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 (und vermeiden Sie AUX.txt usw.)
  • Der Dateiname ist alle Punkte

Einige optionale Dinge zu überprüfen:

  • Dateipfade (einschließlich des Dateinamens) dürfen nicht mehr als 260 Zeichen enthalten (die das \?\Präfix nicht verwenden ).
  • Unicode-Dateipfade (einschließlich des Dateinamens) mit mehr als 32.000 Zeichen bei Verwendung \?\(beachten Sie, dass das Präfix Verzeichniskomponenten erweitern und dazu führen kann, dass das Limit von 32.000 überschritten wird)

8
+1 für das Einschließen reservierter Dateinamen - diese wurden in früheren Antworten übersehen.
SqlRyan

2
"AUX" ist ein perfekt verwendbarer Dateiname, wenn Sie die Syntax "\\? \" Verwenden. Natürlich haben Programme, die diese Syntax nicht verwenden, echte Probleme damit ... (Getestet unter XP)
user9876

9
Die korrekte Regex für alle diese oben genannten Bedingungen ist wie Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
folgt

4
@whywhywhy Ich denke, Sie haben eine zusätzliche Öffnungsklammer in diesem Regex. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\. +) $) (\\ .. *)? $) | (([\\ x00 - \\ x1f \\\\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" arbeitete für mich.
Wilky

4
Ich habe den gleichen Artikel gelesen, der in dieser Antwort erwähnt wurde, und durch Experimente festgestellt, dass COM0 und LPT0 ebenfalls nicht erlaubt sind. @dlf dieser arbeitet mit Dateinamen, die mit '.' beginnen:^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr

67

Für .Net Frameworks vor 3.5 sollte dies funktionieren:

Der Abgleich regulärer Ausdrücke sollte Ihnen einen Teil des Weges erleichtern. Hier ist ein Ausschnitt mit demSystem.IO.Path.InvalidPathChars Konstante.

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

Zum .Net Frameworks nach 3.0 sollte dies funktionieren:

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

Der Abgleich regulärer Ausdrücke sollte Ihnen einen Teil des Weges erleichtern. Hier ist ein Ausschnitt mit derSystem.IO.Path.GetInvalidPathChars() Konstante.

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

Sobald Sie das wissen, sollten Sie auch nach verschiedenen Formaten suchen, z. B. c:\my\driveund\\server\share\dir\file.ext


Testet dies nicht nur den Pfad, nicht den Dateinamen?
Eugene Katz

30
Zeichenfolge strTheseAreInvalidFileNameChars = neue Zeichenfolge (System.IO.Path.GetInvalidFileNameChars ()); Regex regFixFileName = neuer Regex ("[" + Regex.Escape (strTheseAreInvalidFileNameChars) + "]");
Rao

2
Ein wenig Forschung von Menschen würde Wunder wirken. Ich habe den Beitrag aktualisiert, um die Änderungen widerzuspiegeln.
Erik Philips

1
2. Code wird nicht kompiliert. "Kann nicht von char [] in string konvertieren
Paul Hunt

1
@AshkanMobayenKhiabani: InvalidPathChars ist veraltet, GetInvalidPathChars jedoch nicht.
IvanH

25

Versuchen Sie es zu verwenden und suchen Sie nach dem Fehler. Der zulässige Satz kann sich zwischen Dateisystemen oder zwischen verschiedenen Windows-Versionen ändern. Mit anderen Worten, wenn Sie wissen möchten, ob Windows den Namen mag, geben Sie ihm den Namen und lassen Sie sich davon erzählen.


1
Dies scheint der einzige zu sein, der gegen alle Einschränkungen testet. Warum werden die anderen Antworten darüber gewählt?
Lücke

5
@gap weil es nicht immer funktioniert. Beispielsweise ist der Versuch, auf CON zuzugreifen, häufig erfolgreich, obwohl es sich nicht um eine echte Datei handelt.
Antimon

4
Es ist jedoch immer besser, den Speicheraufwand beim Auslösen einer Ausnahme zu vermeiden, sofern dies möglich ist.
Owen Blacker

2
Möglicherweise haben Sie auch keine Berechtigung, darauf zuzugreifen. zB um es schriftlich zu testen, auch wenn Sie es lesen können, wenn es existiert oder existieren wird.
CodeLurker

23

Diese Klasse bereinigt Dateinamen und Pfade. benutze es wie

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

Hier ist der Code;

/// <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
Ihre Antwort könnte hier besser passen: stackoverflow.com/questions/146134/…
nawfal

22

Das benutze ich:

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

Das erste Muster erstellt einen regulären Ausdruck, der die ungültigen / unzulässigen Dateinamen und Zeichen nur für Windows-Plattformen enthält. Der zweite macht dasselbe, stellt jedoch sicher, dass der Name für jede Plattform legal ist.


4
sPattern Regex erlaubt keine Dateien, die mit einem Punktzeichen gestartet wurden. Aber MSDN sagt „es akzeptabel ist , eine Periode als das erste Zeichen eines Namens angeben. Zum Beispiel : “ .temp „“. Ich würde "\ .. *" entfernen, um .gitignore korrekten Dateinamen zu machen :)
yar_shukan

(Ich habe dies schrittweise verbessert und die vorherigen Kommentare gelöscht, die ich hinterlassen habe.) Dieser ist besser als der reguläre Ausdruck der Antwort, da er ".gitignore", "..asdf" zulässt, "<" und ">" oder den Yen nicht zulässt Zeichen, und erlaubt kein Leerzeichen oder Punkt am Ende (was Namen verbietet, die nur aus Punkten bestehen):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr

Dies schlägt für alle von mir getesteten Dateien fehl. Wenn Sie es für C: \ Windows \ System32 \ msxml6.dll ausführen, wird false gemeldet.
magicandre1981

@ magicandre1981 Sie müssen nur den Dateinamen angeben, nicht den vollständig qualifizierten Pfad.
Scott Dorman

ok, aber ich muss überprüfen, ob der vollständige Pfad gültig ist. Ich habe jetzt eine andere Lösung verwendet.
magicandre1981

18

Ein Eckfall, den ich beachten sollte, der mich überraschte, als ich zum ersten Mal davon erfuhr: Windows erlaubt führende Leerzeichen in Dateinamen! Zum Beispiel sind die folgenden alle legalen und unterschiedlichen Dateinamen unter Windows (abzüglich der Anführungszeichen):

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

Eine Erkenntnis daraus: Seien Sie vorsichtig, wenn Sie Code schreiben, der führende / nachfolgende Leerzeichen von einer Dateinamenzeichenfolge trimmt.


10

Vereinfachung der Antwort von Eugene Katz:

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

Oder

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

Meinten Sie: "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Contains (f));" ?
Jack Griffin

@ JackGriffin Natürlich! Vielen Dank für Ihre Aufmerksamkeit.
tmt

Obwohl dieser Code sehr schön zu lesen ist, sollten wir die traurigen Interna von berücksichtigen Path.GetInvalidFileNameChars. Schauen Sie hier nach: referencesource.microsoft.com/#mscorlib/system/io/path.cs,289 - für jedes Zeichen von Ihnen fileNamewird ein Klon des Arrays erstellt.
Piotr Zierhoffer

"DD: \\\\\ AAA ..... AAAA". Nicht gültig, aber für Ihren Code ist es.
Ciccio Pasticcio

8

Microsoft Windows: Der Windows-Kernel verbietet die Verwendung von Zeichen im Bereich 1-31 (dh 0x01-0x1F) und Zeichen "*: <>? \ |. Obwohl NTFS zulässt, dass jede Pfadkomponente (Verzeichnis oder Dateiname) 255 Zeichen lang und länger ist Pfade mit einer Länge von bis zu 32767 Zeichen, der Windows-Kernel unterstützt nur Pfade mit einer Länge von bis zu 259 Zeichen. Außerdem verbietet Windows die Verwendung der MS-DOS-Gerätenamen AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL und PRN sowie diese Namen mit einer beliebigen Erweiterung (z. B. AUX.txt), außer bei Verwendung Lange UNC-Pfade (z. B. \. \ C: \ nul.txt oder \? \ D: \ aux \ con). (Tatsächlich kann CLOCK $ verwendet werden, wenn eine Erweiterung bereitgestellt wird.) Diese Einschränkungen gelten nur für Windows - Linux erlaubt zum Beispiel die Verwendung von "*: <>? \ | sogar in NTFS.

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


1
Ich kann eine Datei mit dem Namen "CLOCK $" erstellen. Windows 7.
rory.ap

7

Anstatt alle möglichen Zeichen explizit einzuschließen, können Sie eine Regex durchführen, um das Vorhandensein unzulässiger Zeichen zu überprüfen und dann einen Fehler zu melden. Im Idealfall sollte Ihre Anwendung die Dateien genau so benennen, wie es der Benutzer wünscht, und nur dann schlecht weinen, wenn ein Fehler auftritt.


6

Die Frage ist, ob Sie versuchen festzustellen, ob ein Pfadname ein zulässiger Windows-Pfad ist oder ob er auf dem System, auf dem der Code ausgeführt wird, zulässig ist.? Ich denke, letzteres ist wichtiger, also würde ich persönlich wahrscheinlich den vollständigen Pfad zerlegen und versuchen, mit _mkdir das Verzeichnis zu erstellen, in das die Datei gehört, und dann versuchen, die Datei zu erstellen.

Auf diese Weise wissen Sie nicht nur, ob der Pfad nur gültige Windows-Zeichen enthält, sondern auch, ob er tatsächlich einen Pfad darstellt, der von diesem Prozess geschrieben werden kann.


6

Ich benutze dies, um ungültige Zeichen in Dateinamen zu entfernen, ohne Ausnahmen auszulösen:

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

Auch CON, PRN, AUX, NUL, COM # und einige andere sind niemals legale Dateinamen in einem Verzeichnis mit einer Erweiterung.


1
Dies ist nur die halbe Wahrheit. Sie können Dateien mit diesen Namen erstellen, wenn Sie die Unicode-Version von CreateFile aufrufen (wobei dem Dateinamen "\\? \" Vorangestellt wird).
Werner Henze

Diese Aussage ist unvollständig und verfehlt LPT #
Thomas Weller

4

Um die anderen Antworten zu ergänzen, finden Sie hier einige zusätzliche Randfälle, die Sie möglicherweise berücksichtigen möchten.


3

In MSDN finden Sie eine Liste von Zeichen, die nicht zulässig sind:

Verwenden Sie fast alle Zeichen auf der aktuellen Codepage für einen Namen, einschließlich Unicode-Zeichen und Zeichen im erweiterten Zeichensatz (128–255), mit Ausnahme der folgenden:

  • Die folgenden reservierten Zeichen sind nicht zulässig: <>: "/ \ |? *
  • Zeichen, deren ganzzahlige Darstellungen im Bereich von Null bis 31 liegen, sind nicht zulässig.
  • Alle anderen Zeichen, die das Zieldateisystem nicht zulässt.

2

Auch das Zieldateisystem ist wichtig.

Unter NTFS können einige Dateien nicht in bestimmten Verzeichnissen erstellt werden. EG $ Boot in root


2
Sicherlich liegt das nicht an einer NTFS-Namensregel, sondern nur daran, dass eine aufgerufene Datei $Bootbereits im Verzeichnis vorhanden ist?
Christian Hayter

2

Dies ist eine bereits beantwortete Frage, aber nur aus Gründen der "anderen Optionen" ist hier eine nicht ideale:

(Nicht ideal, da die Verwendung von Ausnahmen als Flusskontrolle im Allgemeinen eine "schlechte Sache" ist.)

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

Ihr Beispiel hat für eine CON-Datei (C: \ temp \ CON) nicht funktioniert.
Tcbrazil

Aber ist 'C: \ temp \ CON' kein gültiger Dateiname? Warum sollte es nicht sein?
Mark A. Donohoe

@MarqueIV - nein, es ist nicht gültig. Lesen Sie alle Antworten und Kommentare oben oder probieren Sie es selbst aus und sehen Sie.
rory.ap

@Jer, "/ example" ist nicht legal, aber Ihre Methode wird zurückgegeben true.
rory.ap

Aaaah ... Ich habe den 'CON'-Teil verpasst. Der Name selbst ist unter dem Gesichtspunkt der Zeichenfolge gültig (worauf ich mich bezog), aber ich sehe jetzt, dass CON ein reservierter Name ist, was ihn unter dem Gesichtspunkt von Windows ungültig macht. Mein Fehler.
Mark A. Donohoe

2

Reguläre Ausdrücke sind für diese Situation übertrieben. Sie können die String.IndexOfAny()Methode in Kombination mit Path.GetInvalidPathChars()und verwenden Path.GetInvalidFileNameChars().

Beachten Sie auch, dass beide Path.GetInvalidXXX()Methoden ein internes Array klonen und den Klon zurückgeben. Wenn Sie dies also häufig tun (tausende und tausende Male), können Sie eine Kopie des ungültigen Zeichenarrays zur Wiederverwendung zwischenspeichern.


2

Wenn Sie nur versuchen zu überprüfen, ob eine Zeichenfolge, die Ihren Dateinamen / Pfad enthält, ungültige Zeichen enthält, besteht die schnellste Methode, die ich gefunden habe, darin, Split()den Dateinamen in ein Array von Teilen aufzuteilen, wo immer ein ungültiges Zeichen vorhanden ist. Wenn das Ergebnis nur ein Array von 1 ist, gibt es keine ungültigen Zeichen. :-)

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;

Ich habe versucht, diese und andere oben erwähnte Methoden 1.000.000 Mal in LinqPad für einen Datei- / Pfadnamen auszuführen.

Die Verwendung Split()beträgt nur ~ 850 ms.

Die Verwendung Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")dauert ca. 6 Sekunden.

Die komplizierteren regulären Ausdrücke sind VIEL schlimmer, ebenso wie einige der anderen Optionen, wie die Verwendung der verschiedenen Methoden für die PathKlasse, um den Dateinamen abzurufen und ihre interne Validierung den Job erledigen zu lassen (höchstwahrscheinlich aufgrund des Overheads der Ausnahmebehandlung).

Zugegeben, es ist nicht sehr häufig, dass Sie 1 Million Dateinamen validieren müssen, daher ist eine einzelne Iteration für die meisten dieser Methoden ohnehin in Ordnung. Aber es ist immer noch ziemlich effizient und effektiv, wenn Sie nur nach ungültigen Zeichen suchen.


1

Viele dieser Antworten funktionieren nicht, wenn der Dateiname zu lang ist und in einer Umgebung vor Windows 10 ausgeführt wird. Denken Sie auch darüber nach, was Sie mit Punkten tun möchten. Das Zulassen von führenden oder nachfolgenden Zeichen ist technisch gültig, kann jedoch zu Problemen führen, wenn die Datei nicht schwer zu sehen bzw. zu löschen ist.

Dies ist ein Validierungsattribut, das ich erstellt habe, um nach einem gültigen Dateinamen zu suchen.

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

und die Tests

[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

Mein Versuch:

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

Dies ist nicht perfekt, da Path.GetInvalidPathCharsnicht der gesamte Zeichensatz zurückgegeben wird, der in Datei- und Verzeichnisnamen ungültig ist, und natürlich gibt es noch viel mehr Feinheiten.

Also benutze ich diese Methode als Ergänzung:

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

Es wird versucht, die Datei zu erstellen und false zurückzugeben, wenn eine Ausnahme vorliegt. Natürlich muss ich die Datei erstellen, aber ich denke, das ist der sicherste Weg, dies zu tun. Bitte beachten Sie auch, dass ich keine erstellten Verzeichnisse lösche.

Sie können auch die erste Methode verwenden, um eine grundlegende Validierung durchzuführen, und dann die Ausnahmen sorgfältig behandeln, wenn der Pfad verwendet wird.


0

Ich schlage vor, nur den Path.GetFullPath () zu verwenden

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

Fügen Sie eine Erklärung mit Antwort hinzu, wie diese Antwort OP bei der Behebung des aktuellen Problems
hilft

Im Dokument in der MSDN finden Sie die AugumentExcpetion. Sie lautet: Pfad ist eine Zeichenfolge mit der Länge Null, enthält nur Leerzeichen oder enthält eines oder mehrere der in GetInvalidPathChars definierten ungültigen Zeichen. -oder- Das System konnte den absoluten Pfad nicht abrufen.
Tony Sun

Theoretisch (laut Dokumentation) sollte dies funktionieren, das Problem ist jedoch zumindest in .NET Core 3.1 nicht der Fall.
Michel Jansson

0

Ich habe diese Idee von jemandem bekommen. - Ich weiß nicht wer. Lassen Sie das Betriebssystem das schwere Heben erledigen.

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

Diese Prüfung

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

out Namen Filter mit ungültigen Zeichen ( <>:"/\|?*und ASCII 0-31), sowie reservierten DOS - Geräte ( CON, NUL, COMx). Es erlaubt führende Leerzeichen und All-Dot-Namen, die mit übereinstimmen Path.GetFullPath. (Das Erstellen einer Datei mit führenden Leerzeichen ist auf meinem System erfolgreich.)


Verwendet .NET Framework 4.7.1, getestet unter Windows 7.


0

Ein Liner zur Überprüfung illigaler Zeichen in der Zeichenfolge:

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

0

Meiner Meinung nach besteht die einzig richtige Antwort auf diese Frage darin, zu versuchen, den Pfad zu verwenden und das Betriebssystem und das Dateisystem ihn validieren zu lassen. Andernfalls implementieren Sie nur alle Validierungsregeln, die das Betriebssystem und das Dateisystem bereits verwenden, neu (und wahrscheinlich nur unzureichend). Wenn diese Regeln in Zukunft geändert werden, müssen Sie Ihren Code entsprechend ändern.


-1

Windows - Dateinamen sind ziemlich unrestrictive, so wirklich es nicht einmal sein könnte , dass viel von einem Problem. Die von Windows nicht zugelassenen Zeichen sind:

\ / : * ? " < > |

Sie können leicht einen Ausdruck schreiben, um zu überprüfen, ob diese Zeichen vorhanden sind. Eine bessere Lösung wäre jedoch, zu versuchen, die Dateien so zu benennen, wie der Benutzer es wünscht, und sie zu benachrichtigen, wenn ein Dateiname nicht haftet.


Auch Zeichen <= 31 sind verboten.
Antimon
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.