web-dev-qa-db-fra.com

Existe-t-il un moyen en Java de déterminer si un chemin est valide sans tenter de créer un fichier?

Je dois déterminer si une chaîne fournie par l'utilisateur est un chemin de fichier valide (c'est-à-dire si createNewFile () réussira ou lèvera une exception), mais je ne veux pas surcharger le système de fichiers avec des fichiers inutiles créés uniquement à des fins de validation. y at-il un moyen de déterminer si la chaîne que j’ai est un chemin de fichier valide sans essayer de créer le fichier?

Je sais que la définition de "chemin de fichier valide" varie en fonction du système d'exploitation, mais je me demandais s'il existait un moyen rapide d'accepter "C:/toto" ou "/ foo" et de rejeter "banane" ... une approche possible tente peut-être de créer le fichier et de le supprimer éventuellement si la création a réussi, mais j'espère qu'il existe un moyen plus élégant d'obtenir le même résultat ...

54
Raibaz

Cela vérifierait également l'existence du répertoire.

File file = new File("c:\\cygwin\\cygwin.bat");
if (!file.isDirectory())
   file = file.getParentFile();
if (file.exists()){
    ...
}

Il semble que file.canWrite () ne vous indique pas clairement si vous avez le droit d'écrire dans le répertoire.

26
krosenvold

La classe de chemin introduite dans Java 7 ajoute de nouvelles alternatives, telles que:
(Est-ce que not ne fonctionne pas correctement sous Linux - renvoie toujours la valeur true)

/**
 * <pre>
 * Checks if a string is a valid path.
 * Null safe.
 *  
 * Calling examples:
 *    isValidPath("c:/test");      //returns true
 *    isValidPath("c:/te:t");      //returns false
 *    isValidPath("c:/te?t");      //returns false
 *    isValidPath("c/te*t");       //returns false
 *    isValidPath("good.txt");     //returns true
 *    isValidPath("not|good.txt"); //returns false
 *    isValidPath("not:good.txt"); //returns false
 * </pre>
 */
public static boolean isValidPath(String path) {
    try {
        Paths.get(path);
    } catch (InvalidPathException | NullPointerException ex) {
        return false;
    }
    return true;
}
26
c0der

File.getCanonicalPath() est très utile à cette fin. Des exceptions IO sont levées pour certains types de noms de fichiers non valides (par exemple, CON, PRN, *?* sous Windows) lors de la résolution contre le système d'exploitation ou le système de fichiers. Cependant, cela ne sert qu’à titre de vérification préliminaire; vous devrez toujours gérer d’autres échecs lors de la création du fichier (autorisations insuffisantes, manque d’espace disque, restrictions de sécurité, par exemple).

16
Zach Scrivena

Un certain nombre de problèmes peuvent survenir lorsque vous essayez de créer un fichier:

  • Votre manque les autorisations requises;
  • Il n'y a pas assez d'espace sur le périphérique;
  • L'appareil rencontre une erreur; 
  • Certaines politiques de sécurité personnalisée vous empêchent de créer un fichier d'un type particulier;
  • etc.

Plus précisément, ceux-ci peuvent changer entre le moment où vous essayez et la requête pour voir si vous pouvez et quand vous le pouvez réellement. Dans un environnement multithread, il s’agit d’une des causes principales de la concurrence et peut constituer une réelle vulnérabilité de certains programmes.

Fondamentalement, vous devez simplement essayer de le créer et voir si cela fonctionne. Et c'est la bonne façon de le faire. C'est pourquoi des éléments tels que ConcurrentHashMap ont une putIfAbsent(). Le contrôle et l'insertion sont donc des opérations atomiques et ne souffrent pas des conditions de concurrence. C'est exactement le même principe qui est en jeu ici.

Si cela fait simplement partie d'un processus de diagnostic ou d'installation, faites-le et voyez si cela fonctionne. Encore une fois, rien ne garantit que cela fonctionnera plus tard, cependant.

En gros, votre programme doit être suffisamment robuste pour disparaître gracieusement s'il ne peut pas écrire un fichier pertinent.

15
cletus

Voici quelque chose que vous pouvez faire qui fonctionne sur tous les systèmes d'exploitation

Utilisation de la correspondance régulière pour vérifier les caractères non valides existants.

if (newName.matches(".*[/\n\r\t\0\f`?*\\<>|\":].*")) {
    System.out.println("Invalid!");
} else {
    System.out.println("Valid!");
}

Avantages

  • Cela fonctionne sur tous les systèmes d'exploitation
  • Vous pouvez le personnaliser de quelque manière que ce soitvous voulez en éditant cette regex.

Les inconvénients

  • Cela pourrait ne pas être une liste complète et nécessiter plus de recherche pour remplir plus de modèles ou de caractères non valides.
0
Fangming

Faites-le simplement (et nettoyez après vous-même)

Une approche possible peut être de tenter de créer le fichier et éventuellement de le supprimer si la création aboutit, mais j'espère qu'il existe un moyen plus élégant d'obtenir le même résultat.

Peut-être que c'est la manière la plus robuste.

Vous trouverez ci-dessous canCreateOrIsWritable qui détermine si votre programme est capable de créer un fichier et ses répertoires parent sur un chemin donné, ou, s’il ya déjà un fichier, d’y écrire.

Pour ce faire, il crée en fait les répertoires parent nécessaires ainsi qu’un fichier vide sur le chemin. Ensuite, il les supprime (s’il existait un fichier dans le chemin, il restait seul).

Voici comment vous pourriez l'utiliser:

var myFile = new File("/home/me/maybe/write/here.log")

if (canCreateOrIsWritable(myFile)) {
    // We're good. Create the file or append to it
    createParents(myFile);
    appendOrCreate(myFile, "new content");
} else {
    // Let's pick another destination. Maybe the OS's temporary directory:
    var tempDir = System.getProperty("Java.io.tmpdir");
    var alternative = Paths.get(tempDir, "second_choice.log");
    appendOrCreate(alternative, "new content in temporary directory");
}

La méthode essentielle avec quelques méthodes d'assistance:

static boolean canCreateOrIsWritable(File file) {
    boolean canCreateOrIsWritable;

    // The non-existent ancestor directories of the file.
    // The file's parent directory is first
    List<File> parentDirsToCreate = getParentDirsToCreate(file);

    // Create the parent directories that don't exist, starting with the one
    // highest up in the file system hierarchy (closest to root, farthest
    // away from the file)
    reverse(parentDirsToCreate).forEach(File::mkdir);

    try {
        boolean wasCreated = file.createNewFile();
        if (wasCreated) {
            canCreateOrIsWritable = true;
            // Remove the file and its parent dirs that didn't exist before
            file.delete();
            parentDirsToCreate.forEach(File::delete);
        } else {
            // There was already a file at the path → Let's see if we can
            // write to it
            canCreateOrIsWritable = Java.nio.file.Files.isWritable(file.toPath());
        }
    } catch (IOException e) {
        // File creation failed
        canCreateOrIsWritable = false;
    }
    return canCreateOrIsWritable;
}

static List<File> getParentDirsToCreate(File file) {
    var parentsToCreate = new ArrayList<File>();
    File parent = file.getParentFile();
    while (parent != null && !parent.exists()) {
        parentsToCreate.add(parent);

        parent = parent.getParentFile();
    }
    return parentsToCreate;
}

static <T> List<T> reverse(List<T> input) {
    var reversed = new ArrayList<T>();
    for (int i = input.size() - 1; i >= 0; i--) {
        reversed.add(input.get(i));
    }
    return reversed;
}

static void createParents(File file) {
    File parent = file.getParentFile();
    if (parent != null) {
        parent.mkdirs();
    }
}

N'oubliez pas qu'entre l'appel canCreateOrIsWritable et la création du fichier réel, le contenu et les autorisations de votre système de fichiers peuvent avoir changé.

0
Matthias Braun