web-dev-qa-db-fra.com

Valider un nom de fichier sous Windows

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("^[^/./\\:*?\"<>|]+$");
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

Cette méthode garantit-elle un nom de fichier valide sous Windows?

55
Eng.Fouad

Compte tenu des exigences spécifiées dans la précédente documentation MSDN citée , l'expression régulière suivante devrait faire un très bon travail:

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile(
        "# Match a valid Windows filename (unspecified file system).          \n" +
        "^                                # Anchor to start of string.        \n" +
        "(?!                              # Assert filename is not: CON, PRN, \n" +
        "  (?:                            # AUX, NUL, COM1, COM2, COM3, COM4, \n" +
        "    CON|PRN|AUX|NUL|             # COM5, COM6, COM7, COM8, COM9,     \n" +
        "    COM[1-9]|LPT[1-9]            # LPT1, LPT2, LPT3, LPT4, LPT5,     \n" +
        "  )                              # LPT6, LPT7, LPT8, and LPT9...     \n" +
        "  (?:\\.[^.]*)?                  # followed by optional extension    \n" +
        "  $                              # and end of string                 \n" +
        ")                                # End negative lookahead assertion. \n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F]*     # Zero or more valid filename chars.\n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .]  # Last char is not a space or dot.  \n" +
        "$                                # Anchor to end of string.            ", 
        Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS);
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

Notez que cette expression régulière n'impose aucune limite sur la longueur du nom de fichier, mais un vrai nom de fichier peut être limité à 260 ou 32 767 caractères selon la plate-forme.

88
ridgerunner

Pas assez, sous Windows et DOS, certains mots peuvent également être réservés et ne peuvent pas être utilisés comme noms de fichiers.

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.

Voir ~

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


Éditer:

Windows limite généralement les noms de fichiers à 260 caractères. Mais le nom de fichier doit en fait être plus court que cela, car le chemin d'accès complet (tel que C:\Program Files\filename.txt) est inclus dans ce nombre de caractères.

C'est pourquoi vous pouvez parfois rencontrer une erreur lors de la copie d'un fichier avec un nom de fichier très long vers un emplacement dont le chemin d'accès est plus long que son emplacement actuel.

26
Monday

Eh bien, je pense que la méthode suivante garantirait un nom de fichier valide:

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        file.createNewFile();
        if(file.exists()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

Qu'est-ce que tu penses?

16
Eng.Fouad

Une méthode qui garantit, généralement, qu'un nom de fichier Windows est valide - qu'il serait légal de créer un fichier de ce nom - serait impossible à mettre en œuvre.

Il est relativement simple de garantir qu'un nom de fichier Windows est invalide . Certains des autres regex tentent de le faire. Cependant, la question d'origine demande une assertion plus forte: une méthode qui garantit que le nom de fichier est valide sous Windows.

Le référence MSDN cité dans d'autres réponses indique qu'un nom de fichier Windows ne peut pas contenir "tout autre caractère que le système de fichiers cible n'autorise pas". Par exemple, un fichier contenant NUL serait invalide sur certains systèmes de fichiers, tout comme les caractères Unicode étendus sur certains anciens systèmes de fichiers. Ainsi, un fichier appelé ☃.txt serait valide dans certains cas, mais pas dans d'autres. Donc, si une hypothétique isValidName(\"☃\") retournerait vrai dépend du système de fichiers sous-jacent.

Supposons cependant qu'une telle fonction soit conservatrice et nécessite que le nom de fichier soit composé de caractères ASCII imprimables. Toutes les versions modernes de Windows prennent en charge nativement les formats de fichier NTFS, FAT32 et FAT16, qui acceptent les noms de fichiers Unicode. Mais des pilotes pour des systèmes de fichiers arbitraires peuvent être installés, et on est libre de créer un système de fichiers qui ne permet pas, par exemple, la lettre 'n'. Ainsi, même un simple fichier comme "snowman.txt" ne peut pas être "garanti" à être valide.

Mais même en dehors des cas extrêmes, il y a d'autres complications. Par exemple, un fichier nommé "$ LogFile" ne peut pas exister à la racine d'un volume NTFS, mais peut exister ailleurs sur le volume. Ainsi, sans connaître le répertoire, nous ne pouvons pas savoir si "$ LogFile" est un nom valide. Mais même "C:\data\$ LogFile" peut être invalide si, par exemple, "c:\data \" est un lien symbolique vers une autre racine de volume NTFS. (De même, "D:\$ LogFile" peut être valide si D: est un alias d'un sous-répertoire d'un volume NTFS.)

Il y a encore plus de complications. Les flux de données alternatifs sur les fichiers, par exemple, sont légaux sur les volumes NTFS, donc "snowman.txt: ☃" peut être valide. Les trois principaux systèmes de fichiers Windows ont des restrictions de longueur de chemin, donc la validité du nom de fichier est également fonction du chemin. Mais la longueur du chemin physique peut même ne pas être disponible pour isValidName si le chemin est un alias virtuel, un lecteur réseau mappé ou un lien symbolique plutôt qu'un chemin physique sur le volume.

Certains autres ont suggéré une alternative: créer un fichier par le nom proposé puis le supprimer, retournant vrai si et seulement si la création réussit. Cette approche pose plusieurs problèmes pratiques et théoriques. L'une, comme indiqué précédemment, est que la validité est fonction à la fois du nom de fichier et du chemin d'accès, de sorte que la validité de c:\test\☃.txt peut différer de la validité de c:\test2\☃.txt. En outre, la fonction ne parviendrait pas à écrire le fichier pour un certain nombre de raisons non liées à la validité du fichier, telles que l'absence d'autorisation d'écriture dans le répertoire. Un troisième défaut est que la validité d'un nom de fichier n'a pas besoin d'être non déterministe: un système de fichiers hypothétique pourrait, par exemple, ne pas permettre le remplacement d'un fichier supprimé, ou (en théorie) pourrait même décider au hasard si un nom de fichier est valide.

Comme alternative, il est assez simple de créer une méthode isInvalidFileName(String text) qui retourne vrai si le fichier est garanti non valide dans Windows ; les noms de fichiers comme "aux", "*" et "abc.txt". reviendrait vrai. L'opération de création de fichier vérifierait d'abord que le nom de fichier est garanti non valide et, s'il retourne faux, s'arrêterait. Sinon, la méthode pourrait tenter de créer le fichier, tout en étant préparée pour le cas Edge où le fichier ne peut pas être créé car le nom de fichier n'est pas valide.

13
drf

Publier une nouvelle réponse parce que je n'ai pas le seuil de répétition pour commenter le code de Eng.Fouad

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        if(file.createNewFile()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

Un petit changement à votre réponse qui empêche la suppression d'un fichier préexistant. Les fichiers ne sont supprimés que s'ils ont été créés lors de cet appel de méthode, alors que la valeur de retour est la même.

9
Abdul Hfuda

Ici vous pouvez trouver les noms de fichiers autorisés.

Les caractères suivants ne sont pas autorisés:

  • < (Inférieur à)
  • (plus grand que)

  • : (deux points)
  • " (double citation)
  • / (barre oblique)
  • \ (barre oblique inverse)
  • | (barre ou tuyau vertical)
  • ? (point d'interrogation)
  • * (astérisque)

  • Valeur entière zéro, parfois appelée caractère ASCII NUL.

  • Caractères dont les représentations entières sont comprises entre 1 et 31, à l'exception des flux de données alternatifs où ces caractères sont autorisés. Pour plus d'informations sur les flux de fichiers, voir Flux de fichiers.
  • Tout autre caractère non autorisé par le système de fichiers cible.
7
phimuemue

Cela semble bon. Au moins si nous croyons à cette ressource: http://msdn.Microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx

Mais je simplifierais l'utilisation du code. Il suffit de rechercher l'un de ces caractères pour dire que le nom n'est pas valide, donc:

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("[^/./\\:*?\"<>|]");
    return !pattern.matcher(text).find();
}

Cette expression régulière est plus simple et fonctionnera plus rapidement.

6
AlexR

Cette solution vérifie uniquement si un nom de fichier donné est valide selon les règles du système d'exploitation sans créer de fichier.

Vous devez toujours gérer d'autres échecs lors de la création du fichier (par exemple, autorisations insuffisantes, manque d'espace disque, restrictions de sécurité).

import Java.io.File;
import Java.io.IOException;

public class FileUtils {
  public static boolean isFilenameValid(String file) {
    File f = new File(file);
    try {
       f.getCanonicalPath();
       return true;
    }
    catch (IOException e) {
       return false;
    }
  }

  public static void main(String args[]) throws Exception {
    // true
    System.out.println(FileUtils.isFilenameValid("well.txt"));
    System.out.println(FileUtils.isFilenameValid("well well.txt"));
    System.out.println(FileUtils.isFilenameValid(""));

    //false
    System.out.println(FileUtils.isFilenameValid("test.T*T"));
    System.out.println(FileUtils.isFilenameValid("test|.TXT"));
    System.out.println(FileUtils.isFilenameValid("te?st.TXT"));
    System.out.println(FileUtils.isFilenameValid("con.TXT")); // windows
    System.out.println(FileUtils.isFilenameValid("prn.TXT")); // windows
    }
  }
6
RealHowTo

Je ne sais pas comment l'implémenter dans Java (Regex ou méthode propre). Mais, le système d'exploitation Windows a les règles suivantes pour créer un fichier/répertoire dans le système de fichiers:

  1. Le nom n'est pas seulement des points
  2. Les noms de périphériques Windows comme AUX, CON, NUL, PRN, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, ne peuvent pas être utilisé pour un nom de fichier ni pour le premier segment d'un nom de fichier (c'est-à-dire test1 dans test1.txt).
  3. Les noms de périphériques ne respectent pas la casse. (c.-à-d. prn, PRN, Prn, etc. sont identiques.)
  4. Tous les caractères supérieurs à ASCII 31 à utiliser sauf "* /: <>?\|

Le programme doit donc respecter ces règles. J'espère que cela couvre les règles de validation de votre question.

2
Ganesan

Vous pouvez vérifier tous les noms réservés (AUX, CON, etc.), puis utiliser ce code:

bool invalidName = GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES && 
        GetLastError() == ERROR_INVALID_NAME;

pour vérifier toute restriction supplémentaire. Mais notez que si vous recherchez un nom dans un répertoire inexistant, vous obtiendrez ERROR_PATH_NOT_FOUND si le nom est vraiment valide ou non.

Quoi qu'il en soit, vous devez vous rappeler le vieil adage:

Il est plus facile de demander pardon que d'obtenir la permission.

1
rodrigo