Come posso verificare se una determinata stringa è un nome file legale / valido in Windows?


165

Voglio includere una funzionalità di ridenominazione di file batch nella mia applicazione. Un utente può digitare un modello di nome file di destinazione e (dopo aver sostituito alcuni caratteri jolly nel modello) ho bisogno di verificare se sarà un nome file legale in Windows. Ho provato a usare un'espressione regolare come, [a-zA-Z0-9_]+ma non include molti caratteri specifici nazionali di varie lingue (ad esempio, umlaut e così via). Qual è il modo migliore per fare un simile controllo?


Suggerisco di utilizzare un Regex compilato statico se si intende utilizzare una delle risposte con Regex ..
AMissico,

Risposte:


100

È possibile ottenere un elenco di caratteri non validi da Path.GetInvalidPathCharse GetInvalidFileNameChars.

UPD: vedi il suggerimento di Steve Cooper su come usarli in un'espressione regolare.

UPD2: Notare che, in base alla sezione Note in MSDN "L'array restituito da questo metodo non è garantito per contenere l'insieme completo di caratteri non validi nei nomi di file e directory". La risposta fornita da sixlettervaliables entra in maggiori dettagli.


11
Questo non risponde alla domanda; ci sono molte stringhe composte solo da caratteri validi (ad esempio "....", "CON", stringhe lunghe centinaia di caratteri) che non sono nomi di file validi.
Dour High Arch,

31
Qualcun altro ha deluso il fatto che MS non fornisca funzionalità / API a livello di sistema per questa capacità invece che ogni sviluppatore deve cucinare la propria soluzione? Mi chiedo se c'è una buona ragione per questo o solo una svista da parte della SM.
Thomas Nguyen,

@High Arch: vedi la risposta alla domanda "In C # controlla che il nome del file sia probabilmente valido (non che esista)". (Anche se alcuni ragazzi intelligenti hanno chiuso la domanda a favore di questa ...)
mmmmmmmm

129

Da "Naming a File or Directory" di MSDN, ecco le convenzioni generali per quale sia il nome di un file legale in Windows:

È possibile utilizzare qualsiasi carattere nella tabella codici corrente (Unicode / ANSI sopra 127), tranne:

  • < > : " / \ | ? *
  • Caratteri le cui rappresentazioni di numeri interi sono 0-31 (inferiore allo spazio ASCII)
  • Qualsiasi altro carattere non consentito dal file system di destinazione (ad esempio periodi o spazi finali)
  • Uno dei nomi DOS: CON, PRN, AUX, NUL, COM0, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9 (ed evitare AUX.txt, ecc.)
  • Il nome del file è tutti i periodi

Alcune cose opzionali da controllare:

  • I percorsi dei file (incluso il nome del file) non possono contenere più di 260 caratteri (che non utilizzano il \?\prefisso)
  • Percorsi di file Unicode (incluso il nome del file) con più di 32.000 caratteri durante l'utilizzo \?\(notare che il prefisso può espandere i componenti della directory e causare il superamento del limite di 32.000)

8
+1 per l'inclusione di nomi di file riservati: mancavano quelle nelle risposte precedenti.
SqlRyan,

2
"AUX" è un nome file perfettamente utilizzabile se si utilizza la sintassi "\\? \". Ovviamente, i programmi che non usano quella sintassi hanno veri problemi a
gestirla

9
La regex corretta per tutte queste condizioni sopra menzionate è la seguente:Regex unspupportedRegex = new Regex("(^(PRN|AUX|NUL|CON|COM[1-9]|LPT[1-9]|(\\.+)$)(\\..*)?$)|(([\\x00-\\x1f\\\\?*:\";|/<>])+)|(([\\. ]+)", RegexOptions.IgnoreCase);
whywhywhy perché il

4
@whywhywhy Penso che tu abbia una parentesi di apertura extra in quel Regex. "(^ (PRN | AUX | NUL | CON | COM [1-9] | LPT [1-9] | (\\ +) $) (\\ .. *) $.?) | (([\\ x00 - \\ x1f \\\\? *: \ "; ‌ | / <>]) +) | ([\\.] +)" ha funzionato per me.
Wilky,

4
Ho letto lo stesso articolo menzionato in questa risposta e ho scoperto, attraverso la sperimentazione, che anche COM0 e LPT0 non sono ammessi. @dlf questo funziona con nomi di file che iniziano con '.':^(?!^(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)(?:\.*?(?!\.))[^\x00-\x1f\\?*:\";|\/<>]+(?<![\s.])$
mjohnsonengr

67

Per .Net Frameworks precedente alla 3.5 dovrebbe funzionare:

La corrispondenza delle espressioni regolari dovrebbe aiutarti. Ecco uno snippet che utilizza la System.IO.Path.InvalidPathCharscostante;

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

Per .Net Frameworks dopo 3.0 questo dovrebbe funzionare:

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

La corrispondenza delle espressioni regolari dovrebbe aiutarti. Ecco uno snippet che utilizza la System.IO.Path.GetInvalidPathChars()costante;

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

Una volta che lo sai, dovresti anche controllare diversi formati, ad esempio c:\my\drivee\\server\share\dir\file.ext


questo non verifica solo il percorso, non il nome file?
Eugene Katz,

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

2
Una piccola ricerca da parte della gente farebbe miracoli. Ho aggiornato il post per riflettere le modifiche.
Erik Philips,

1
Il secondo pezzo di codice non viene compilato. "Impossibile convertire da char [] a stringa
Paul Hunt,

1
@AshkanMobayenKhiabani: InvalidPathChars è obsoleto, mentre GetInvalidPathChars no.
IvanH

25

Prova a usarlo e intercetta l'errore. Il set consentito può cambiare tra i file system o tra diverse versioni di Windows. In altre parole, se vuoi sapere se a Windows piace il nome, passa il nome e lascia che te lo dica.


1
Questo sembra essere l'unico che mette alla prova tutti i vincoli. Perché le altre risposte vengono scelte al riguardo?
gap

5
@gap perché non sempre funziona. Ad esempio, il tentativo di accedere a CON spesso avrà successo, anche se non è un file reale.
Antimonio

4
Tuttavia, è sempre meglio evitare il sovraccarico di memoria derivante dal generare un'eccezione, laddove possibile.
Owen Blacker,

2
Inoltre, potresti non avere le autorizzazioni per accedervi; ad esempio per testarlo scrivendo, anche se puoi leggerlo se esiste o esisterà.
CodeLurker,

23

Questa classe pulisce nomi di file e percorsi; usalo come

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

Ecco il codice;

/// <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
la risposta potrebbe essere adatta meglio qui: stackoverflow.com/questions/146134/...
Nawfal

22

Questo è quello che uso:

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

Il primo modello crea un'espressione regolare contenente i nomi e i caratteri di file non validi / illegali solo per piattaforme Windows. Il secondo fa lo stesso ma garantisce che il nome sia legale per qualsiasi piattaforma.


4
sPattern regex non consente i file avviati con il carattere punto. Ma MSDN dice "è accettabile specificare un punto come primo carattere di un nome. Ad esempio" .temp "". Vorrei rimuovere "\ .. *" per rendere .gitignore il nome file corretto :)
yar_shukan

(L'ho migliorato progressivamente e ho eliminato i commenti precedenti che ho lasciato) Questo è migliore della regex della risposta perché consente ".gitignore", "..asdf", non consente "<" e ">" o lo yen segno e non consente lo spazio o il punto alla fine (che non consente i nomi costituiti solo da punti):@"^(?!(?:PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d)(?:\..+)?$)[^\x00-\x1F\xA5\\?*:\"";|\/<>]+(?<![\s.])$"
mjohnsonengr

questo non riesce per tutti i file che ho testato. eseguendolo per C: \ Windows \ System32 \ msxml6.dll riporta false.
magicandre1981,

@ magicandre1981 Devi dargli solo il nome del file, non il percorso completo.
Scott Dorman,

ok, ma devo verificare se il percorso completo è valido. Ho usato ora una soluzione diversa.
magicandre1981,

18

Un caso da tenere a mente, che mi ha sorpreso quando l'ho scoperto per la prima volta: Windows consente di inserire i caratteri spaziali nei nomi dei file! Ad esempio, i seguenti sono tutti nomi di file legali e distinti su Windows (meno le virgolette):

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

Uno da asporto da questo: prestare attenzione quando si scrive il codice che taglia gli spazi bianchi iniziali / finali da una stringa di nome file.


10

Semplificare la risposta di Eugene Katz:

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

O

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

Intendevi forse "return! FileName.Any (f => Path.GetInvalidFileNameChars (). Contiene (f));" ?
Jack Griffin,

@JackGriffin Certo! Grazie per la tua attenzione.
tmt

Mentre questo codice è molto bello da leggere, dovremmo prendere in considerazione i dispiaciuti interni di Path.GetInvalidFileNameChars. Dai un'occhiata qui: riferimentiource.microsoft.com/#mscorlib/system/io/path.cs.289 - per ogni personaggio del tuo fileName, viene creato un clone dell'array.
Piotr Zierhoffer,

"DD: \\\\\ AAA ..... AAAA". Non valido, ma per il tuo codice lo è.
Ciccio Pasticcio

8

Microsoft Windows: il kernel di Windows proibisce l'uso di caratteri nell'intervallo 1-31 (ovvero 0x01-0x1F) e caratteri "*: <>? \ |. Sebbene NTFS consenta che ogni componente del percorso (directory o nome file) sia lungo 255 caratteri e percorsi lunghi fino a circa 32767 caratteri, il kernel di Windows supporta solo percorsi lunghi fino a 259. Inoltre, Windows proibisce l'uso dei nomi dei dispositivi MS-DOS AUX, CLOCK $, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, CON, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, NUL e PRN, nonché questi nomi con qualsiasi estensione (ad esempio, AUX.txt), tranne quando si utilizza Percorsi UNC lunghi (es. \. \ C: \ nul.txt o \? \ D: \ aux \ con). (In realtà, CLOCK $ può essere utilizzato se viene fornita un'estensione.) Queste restrizioni si applicano solo a Windows - Linux, ad esempio, consente l'uso di "*: <>? \ | anche in NTFS.

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


1
Posso creare un file chiamato "CLOCK $" bene. Windows 7.
rory.ap,

7

Invece di includere esplicitamente tutti i possibili personaggi, potresti fare una regex per verificare la presenza di caratteri illegali e segnalare un errore. Idealmente, l'applicazione dovrebbe nominare i file esattamente come desidera l'utente e piangere solo se si imbatte in un errore.


6

La domanda è: stai cercando di determinare se un nome percorso è un percorso Windows legale o se è legale sul sistema in cui è in esecuzione il codice. ? Penso che quest'ultimo sia più importante, quindi personalmente, probabilmente decomponerei il percorso completo e proverei a usare _mkdir per creare la directory a cui appartiene il file, quindi provare a creare il file.

In questo modo sai non solo se il percorso contiene solo caratteri Windows validi, ma se in realtà rappresenta un percorso che può essere scritto da questo processo.


6

Lo uso per eliminare i caratteri non validi nei nomi dei file senza generare eccezioni:

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

Inoltre CON, PRN, AUX, NUL, COM # e pochi altri non sono mai nomi di file legali in qualsiasi directory con alcuna estensione.


1
Questa è solo metà della verità. È possibile creare file con questi nomi se si chiama la versione unicode di CreateFile (prefissando il nome del file con "\\? \").
Werner Henze,

Questa affermazione è incompleta e manca LPT #
Thomas Weller,


3

Da MSDN , ecco un elenco di caratteri non consentiti:

Utilizzare quasi tutti i caratteri nella tabella codici corrente per un nome, inclusi i caratteri Unicode e i caratteri nel set di caratteri esteso (128–255), ad eccezione di quanto segue:

  • Non sono consentiti i seguenti caratteri riservati: <>: "/ \ |? *
  • Non sono consentiti caratteri le cui rappresentazioni di numeri interi sono comprese nell'intervallo da zero a 31.
  • Qualsiasi altro carattere non consentito dal file system di destinazione.

2

Anche il file system di destinazione è importante.

In NTFS, alcuni file non possono essere creati in directory specifiche. EG $ Boot in root


2
Sicuramente ciò non è dovuto a una regola di denominazione NTFS, ma semplicemente perché $Bootesiste già un file chiamato nella directory?
Christian Hayter,

2

Questa è una domanda a cui è già stata data una risposta, ma solo per motivi di "Altre opzioni", eccone una non ideale:

(non ideale perché l'uso delle eccezioni come controllo di flusso è una "cosa negativa", in genere)

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

Il tuo esempio non ha funzionato per un file CON (C: \ temp \ CON).
tcbrazil

Ma "C: \ temp \ CON" non è un nome file valido? Perché non dovrebbe essere?
Mark A. Donohoe,

@MarqueIV - no, non è valido. Leggi tutte le risposte e i commenti sopra o provalo tu stesso e vedi.
rory.ap,

@Jer, "/ example" non è legale, ma il tuo metodo ritorna true.
rory.ap,

Aaaah ... Ho perso la parte "CON". Il nome stesso è valido dal punto di vista della stringa (che è ciò a cui mi riferivo), ma ora vedo CON è un nome riservato, che lo rende non valido dal punto di vista di Windows. Colpa mia.
Mark A. Donohoe,

2

Le espressioni regolari sono eccessive per questa situazione. È possibile utilizzare il String.IndexOfAny()metodo in combinazione con Path.GetInvalidPathChars()e Path.GetInvalidFileNameChars().

Si noti inoltre che entrambi i Path.GetInvalidXXX()metodi clonano un array interno e restituiscono il clone. Quindi, se lo farai molto (migliaia e migliaia di volte) puoi memorizzare nella cache una copia dell'array di caratteri non validi per il riutilizzo.


2

Se stai solo cercando di verificare se una stringa che contiene il nome / percorso del tuo file ha caratteri non validi, il metodo più veloce che ho trovato è quello di utilizzare Split()per dividere il nome del file in una matrice di parti ovunque sia presente un carattere non valido. Se il risultato è solo un array di 1, non ci sono caratteri non validi. :-)

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;

Ho provato a eseguire questo e altri metodi sopra menzionati su un nome di file / percorso 1.000.000 di volte in LinqPad.

L'uso Split()è di soli ~ 850ms.

L'utilizzo Regex("[" + Regex.Escape(new string(System.IO.Path.GetInvalidPathChars())) + "]")è di circa 6 secondi.

Le espressioni regolari più complicate peggiorano MOLTO peggio, così come alcune delle altre opzioni, come l'uso dei vari metodi sulla Pathclasse per ottenere il nome del file e lasciare che la loro convalida interna faccia il lavoro (molto probabilmente a causa del sovraccarico della gestione delle eccezioni).

Concesso che non molto spesso è necessario convalidare 1 milione di nomi di file, quindi una singola iterazione va bene comunque per la maggior parte di questi metodi. Ma è ancora abbastanza efficiente ed efficace se stai cercando solo personaggi non validi.


1

molte di queste risposte non funzioneranno se il nome del file è troppo lungo e in esecuzione in un ambiente precedente a Windows 10. Allo stesso modo, pensa a cosa vuoi fare con i periodi: consentire il vantaggio o il trailing è tecnicamente valido, ma può creare problemi se non vuoi che il file sia difficile da vedere o eliminare rispettivamente.

Questo è un attributo di convalida che ho creato per verificare la presenza di un nome file valido.

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

e i test

[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

Il mio tentativo:

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

Questo non è perfetto perché Path.GetInvalidPathCharsnon restituisce il set completo di caratteri non validi nei nomi di file e directory e ovviamente ci sono molte più sottigliezze.

Quindi uso questo metodo come complemento:

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

Prova a creare il file e restituisce false se esiste un'eccezione. Certo, devo creare il file ma penso che sia il modo più sicuro per farlo. Si noti inoltre che non sto eliminando le directory che sono state create.

È inoltre possibile utilizzare il primo metodo per eseguire la convalida di base e quindi gestire attentamente le eccezioni quando viene utilizzato il percorso.


0

Suggerisco di usare Path.GetFullPath ()

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

Aggiungi una spiegazione con la risposta su come questa risposta aiuta OP nel risolvere il problema attuale
ρяσѕρєя K

Vedere il documento in MSDN per AugumentExcpetion, recita: path è una stringa di lunghezza zero, contiene solo uno spazio bianco o contiene uno o più caratteri non validi definiti in GetInvalidPathChars. - oppure - Il sistema non è riuscito a recuperare il percorso assoluto.
Tony Sun,

In teoria (secondo i documenti) questo dovrebbe funzionare, il problema è sebbene almeno in .NET Core 3.1, non funziona.
Michel Jansson,

0

Ho avuto questa idea da qualcuno. - non so chi. Lascia che il sistema operativo esegua il sollevamento di carichi pesanti.

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

Questo controllo

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

filtri fuori i nomi con caratteri non validi ( <>:"/\|?*e ASCII 0-31), così come i dispositivi DOS riservati ( CON, NUL, COMx). Permette spazi iniziali e nomi di tutti i punti, coerenti con Path.GetFullPath. (La creazione di file con spazi iniziali ha esito positivo sul mio sistema).


Usato .NET Framework 4.7.1, testato su Windows 7.


0

Una riga per la verifica dei caratteri illigali nella stringa:

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

0

A mio avviso, l'unica risposta corretta a questa domanda è provare a utilizzare il percorso e consentire al sistema operativo e al file system di convalidarlo. Altrimenti stai semplicemente reimplementando (e probabilmente male) tutte le regole di convalida che il sistema operativo e il filesystem già utilizzano e se tali regole verranno modificate in futuro dovrai cambiare il tuo codice per abbinarle.


-1

I nomi dei file di Windows sono piuttosto restrittivo, quindi in realtà non potrebbe anche essere che molto di un problema. I caratteri non consentiti da Windows sono:

\ / : * ? " < > |

Puoi facilmente scrivere un'espressione per verificare se questi caratteri sono presenti. Una soluzione migliore sarebbe quella di provare a nominare i file come desidera l'utente e avvisarli quando un nome file non si attacca.


Anche i caratteri <= 31 sono vietati.
Antimonio
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.