2009-05-21 7 views
45

Dans mon application Java, je renomme les fichiers en un nom de fichier fourni dans un paramètre String. Il existe une méthodeJava - Comment savoir si un nom de fichier est valide?

boolean OKtoRename(String oldName, String newName) 

qui vérifie essentiellement si le newName est pas déjà pris par un autre fichier, comme je ne voudrais pas enterrer ceux qui existent déjà.

Il m'est maintenant apparu que peut-être le nouveau nom Chaîne ne dénotera pas un nom de fichier valide. Donc je pensais que d'ajouter ce chèque à la méthode:

if (new File(newName).isFile()) { 
    return false; 
} 

Ce qui est évidemment pas la bonne façon de le faire, puisque dans la plupart des cas, le newFile n'existe pas encore et donc bien qu'il est OKtoRename, la La fonction renvoie false.

Je me demandais, est-il une méthode (je sais qu'il n'y a pas pour les objets java.io.File) comme canExist()? Ou devrais-je utiliser regex pour m'assurer que la chaîne newFile ne contient pas de caractères invalides (par exemple?, *, ", :)? Je me demande s'il y a peut-être une fonction cachée quelque part dans le JDK pourrait éventuellement indiquer un nom de fichier valide.

+0

s'il vous plaît, pas plus de réponses existe(), ce n'est pas utile. J'essaie de vérifier si un fichier pourrait exister. –

+1

@MasterPeter: Essayez de reformuler votre question. Au début, il semble que vous voulez savoir si le fichier existe, alors que vous avez réellement besoin de savoir si le fichier NAME est valide. J'ai changé le titre, mais je n'ai pas touché à la formulation de la question. – OscarRyz

+0

Cela semble pertinent: http://eng-przemelek.blogspot.com/2009/07/how-to-create-valid-file-name.html – greenoldman

Répondre

21

Utilisez createNewFile(), qui va créer atomiquement le fichier que si elle n'existe pas encore.

Si le fichier est créé, le nom est valide et il n'est pas en train d'écraser une fichier existant.Vous pouvez ensuite ouvrir les fichiers et copier efficacement les données de l'un à l'autre avec FileChannel.transferXXX opérations

Une chose importante à garder à l'esprit que, en général, le contrôle et le la création devrait être atomique. Si vous vérifiez d'abord si une opération est sûre, effectuez l'opération comme une étape distincte, les conditions peuvent avoir changé entre-temps, rendant l'opération dangereuse.

nourriture supplémentaire pour la pensée est disponible à ce poste connexe: "Move/Copy operations in Java."


Mise à jour:

Depuis cette réponse, les API NIO.2 ont été introduites, qui ajoutent une plus grande interaction avec les système de fichiers. Supposons que vous ayez un programme interactif et que vous souhaitiez valider après chaque frappe si le fichier est potentiellement valide. Par exemple, vous pouvez activer un bouton "Enregistrer" uniquement lorsque l'entrée est valide au lieu d'ouvrir une boîte de dialogue d'erreur après avoir appuyé sur "Enregistrer". Créer et assurer la suppression de beaucoup de fichiers inutiles que ma suggestion ci-dessus exigerait semble être un gâchis. Avec NIO.2, vous ne pouvez pas créer une instance Path contenant des caractères qui sont illégaux pour le système de fichiers. Un InvalidPathException est déclenché dès que vous essayez de créer le Path.

Cependant, il n'y a pas d'API pour valider les noms illégaux composés de caractères valides, comme "PRN" sous Windows. Comme solution de contournement, l'expérimentation a montré que l'utilisation d'un nom de fichier illégal soulèverait une exception distincte lors de la tentative d'accès aux attributs (en utilisant Files.getLastModifiedTime(), par exemple).

Si vous spécifiez un nom légal pour un fichier qui existe, vous n'obtenez aucune exception.

Si vous spécifiez un nom légal pour un fichier qui n'existe pas, il lève NoSuchFileException.

Si vous spécifiez un nom non autorisé, FileSystemException est déclenché.

Cependant, cela semble très kludgey et pourrait ne pas être fiable sur d'autres systèmes d'exploitation.

+2

Vous voudrez cependant supprimer le fichier que vous venez de créer, car la fonction OKtoRename ne doit pas vraiment changer le système de fichiers, répondez simplement si le nom du fichier fonctionnera. –

+1

@Matt: Ooor, vous venez de créer le fichier et si createNewFile renvoie false, cela signifie que le nom de fichier n'était pas valide (... ou ne pouvait pas être créé: -S) ¬¬ exactement – OscarRyz

+0

, je pense que je vais aller avec cette solution mais je n'aime pas l'idée de créer un fichier vide juste pour le supprimer immédiatement après ... –

57

J'ai assemblé une liste de caractères de noms de fichiers illégaux (en considérant les systèmes UNIX, Mac OS X et Windows) sur la base d'une recherche en ligne il y a quelques mois. Si le nouveau nom de fichier contient l'un de ces éléments, il existe un risque qu'il ne soit pas valide sur toutes les plates-formes.

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' }; 

EDIT: Je voudrais souligner que c'est pas une solution complète: comme commentateur a fait remarquer, même si elle passe ce test votre nom de fichier peut encore être un mot-clé spécifique à Windows COM, PRN, etc. Cependant, si votre nom de fichier contient l'un de ces caractères, il causera certainement des problèmes dans un environnement multi-plateforme.

+10

Mais ne pas oublier les mots-clés, comme essayer de créer un fichier appelé COM, COM1, COM2, PRN, etc. (au moins sur les plates-formes Windows) – Instantsoup

+0

Point prise, n'ont même pas pensé à cela ... –

+1

pendant que je réalise Ce n'est pas une solution complète, cela a bien fonctionné pour moi (où seulement une partie du nom de fichier est dynamique et donc les mots clés ne sont pas un risque). merci de compiler cette liste. – radai

2

Pour moi, il semble être un problème dépendant du système d'exploitation. Vous pouvez simplement vouloir vérifier un caractère non valide dans le nom du fichier. Windows le fait lorsque vous essayez de renommer le fichier, il affiche un message indiquant qu'un fichier ne peut contenir aucun des caractères suivants: \ /: *? <> | Je ne suis pas sûr si votre question est "est là une bibliothèque faisant le travail pour moi?" dans ce cas je n'en connais pas.

+2

on devrait probablement aussi vérifier la longueur du nom de fichier. –

0

En utilisant

String validName = URLEncoder.encode(fileName , "UTF-8"); 

File newFile = new File(validName); 

Est-ce que le travail.

Je viens de trouver aujourd'hui. Je ne suis pas sûr que cela fonctionne à 100% du temps, mais jusqu'à présent, j'ai pu créer des noms de fichiers valides.

+4

Désolé, mais s'il y avait des étoiles dans le nom de fichier, votre code n'aiderait pas. System.out.println (URLEncoder.encode ("* hello world *", "UTF-8")); imprime * Bonjour + monde * Et ce ne serait pas un nom de fichier valide. –

+0

Super! .. Vous avez raison, en fait, j'étais sur le point de demander cela. :) – OscarRyz

4

Voilà comment je mis en œuvre ceci: manière spécifique

public boolean isValidFileName(final String aFileName) { 
    final File aFile = new File(aFileName); 
    boolean isValid = true; 
    try { 
     if (aFile.createNewFile()) { 
      aFile.delete(); 
     } 
    } catch (IOException e) { 
     isValid = false; 
    } 
    return isValid; 
} 
+2

Cela conduit à un bug de sécurité de traversée de répertoire. Ce n'est pas un moyen de codage sécurisé si le nom du fichier provient d'un tiers. –

+0

@VishnuPrasadKallummel Une traversée de répertoire consiste à exploiter une validation/désinfection de sécurité insuffisante des noms de fichier d'entrée fournis par l'utilisateur. Vous devriez avoir une couche différente dans votre application pour effectuer la désinfection. Pouvez-vous expliquer pourquoi vous considérez que la validation des entrées utilisateur doit être mélangée dans une méthode qui valide si un chemin donné est valide? –

+0

Cette méthode en tant que telle sera un problème de traversée de répertoire. Mais si vous avez une couche supplémentaire où vous vérifiez avant que cette méthode soit appelée, cela semble correct. C'était un commentaire spontané car je cherchais la même chose sans réellement créer un fichier et ensuite le supprimer. –

16

système Here est suggéré.

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

Oh mon dieu, je n'ai pas vu ta réponse ... –

+1

belle solution mais malheureusement ça ne marche pas sur Android :-(iefgetCanonicalPath() ne lance pas d'exception pour les noms de fichiers incorrects –

+6

N'est-ce pas risqué de compter sur une fonction qui n'est [pas faite pour le travail] (http://docs.oracle.com/javase/7/docs/api/java/io/File.html#getCanonicalFile())? – Nielsvh

4

Si le développement d'Eclipse, consultez org.eclipse.core.internal.resources.OS

public abstract class OS { 
    private static final String INSTALLED_PLATFORM; 

    public static final char[] INVALID_RESOURCE_CHARACTERS; 
    private static final String[] INVALID_RESOURCE_BASENAMES; 
    private static final String[] INVALID_RESOURCE_FULLNAMES; 

    static { 
     //find out the OS being used 
     //setup the invalid names 
     INSTALLED_PLATFORM = Platform.getOS(); 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp 
     INVALID_RESOURCE_CHARACTERS = new char[] {'\\', '/', ':', '*', '?', '"', '<', '>', '|'}; 
     INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 
       "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ 
       "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ 
     Arrays.sort(INVALID_RESOURCE_BASENAMES); 
     //CLOCK$ may be used if an extension is provided 
     INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$ 
     } else { 
     //only front slash and null char are invalid on UNIXes 
     //taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html 
     INVALID_RESOURCE_CHARACTERS = new char[] {'/', '\0',}; 
     INVALID_RESOURCE_BASENAMES = null; 
     INVALID_RESOURCE_FULLNAMES = null; 
     } 
    } 

    /** 
    * Returns true if the given name is a valid resource name on this operating system, 
    * and false otherwise. 
    */ 
    public static boolean isNameValid(String name) { 
     //. and .. have special meaning on all platforms 
     if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$ 
     return false; 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //empty names are not valid 
     final int length = name.length(); 
     if (length == 0) 
      return false; 
     final char lastChar = name.charAt(length-1); 
     // filenames ending in dot are not valid 
     if (lastChar == '.') 
      return false; 
     // file names ending with whitespace are truncated (bug 118997) 
     if (Character.isWhitespace(lastChar)) 
      return false; 
     int dot = name.indexOf('.'); 
     //on windows, filename suffixes are not relevant to name validity 
     String basename = dot == -1 ? name : name.substring(0, dot); 
     if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0) 
      return false; 
     return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0; 
     } 
     return true; 
    } 
} 
+2

Ceci est accessible via' org.eclipse.core.resources.IWorkspace.validateName (String, int) ' – Basilevs

2

quelque chose que je trouve, en Java 7 et plus tard, il y a une classe appelée Paths qui a une méthode appelée get qui prend un ou plusieurs String s et jette

InvalidPathException - si la chaîne de chemin ne peut pas être converti en un chemin

+0

cela vaut la peine d'essayer –

+0

Une chose à noter: sur systèmes basés sur unix, ce sont des noms de fichiers valides: "salut!", "Bonjour fichier", "vraiment?" Au travail nous trouvé cette approche permettait à ceux-ci de passer. – lordoku

Questions connexes