FAQ Fichiers, flux et réseauxConsultez toutes les FAQ
Nombre d'auteurs : 15, nombre de questions : 95, dernière mise à jour : 21 mars 2016 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur le forum Java de http://java.developpez.com ainsi que l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- Comment référencer un fichier ou un répertoire ?
- Comment connaître la taille d'un fichier ?
- Comment connaître la date de création d'un fichier ?
- Comment connaître la date de modification d'un fichier ?
- Comment connaître l'espace libre d'un disque ?
- Comment connaître les racines des arborescences de fichiers ?
- Comment indiquer la position d'un fichier en conservant la portabilité ?
- Comment tester si on manipule un fichier ou un répertoire ou un lien ?
- Comment lister le contenu d'un répertoire ?
- Comment parcourir une arborescence de fichiers ?
- Comment supprimer un fichier ou un répertoire ?
- Comment renommer/déplacer un fichier ?
- Comment copier un fichier ?
- Comment déplacer un fichier vers un autre disque physique ?
- Comment connaître le type MIME d'un fichier ?
- Comment créer un fichier temporaire ?
- Comment savoir si un fichier est accessible ou exécutable ?
- Comment savoir quels types d'attributs sont supportés par le système de fichiers ?
- Comment obtenir les attributs d'un fichier ?
- Comment gérer les permissions sur un fichier ?
Un fichier est une sorte de pointeur qui permet d’accéder à un bloc de données, généralement stocké sur un disque dur. On peut accéder à un fichier en utilisant un chemin qui définit assez souvent une arborescence depuis une des racines du système de fichiers.
Dans la plupart des systèmes de fichiers, la notion de répertoire permet de définir un parent à des fichiers qui ont une partie commune dans leur chemin. Souvent, un répertoire peut contenir un fichier ou pseudofichier nommé « . » qui définit le répertoire lui-même et un fichier ou pseudofichier nommé « .. » qui définit son répertoire parent.
Beaucoup de systèmes d'exploitation permettent également de définir des liens symboliques (symbolic link ou symlink) qui sont des sortes de raccourcis transparents vers d'autres fichiers qui peuvent être situés ailleurs. Il est également possible de définir des liens matériels (hard link) qui permettent à plusieurs fichiers de pointer vers la même donnée sur le disque dur. Il est important de retenir que :
- un lien symbolique est un fichier qui pointe vers un autre fichier. Si la source du lien est effacée, le bloc de données pointé par le fichier source est perdu ; le lien existe toujours, mais devient non valide ;
- un lien matériel est un fichier qui pointe vers un bloc de données qui peut être déjà référencé par au moins un autre fichier. Ces liens fonctionnent donc comme des fichiers normaux et tant qu'il reste un fichier qui pointe vers un bloc, ce dernier n'est pas effacé.
Note : sur les versions récentes de Windows, il est possible de créer des liens avec la commande mklink.
Il existe plusieurs manières de référencer une ressource dans un système de fichiers.
Chaine de caractères
La manière la plus basique de référencer un fichier est tout simplement de stocker son nom dans une variable de type String. Certaines portions de l'API permettent d'utiliser une simple chaine de caractères pour passer un chemin dans une méthode ou un constructeur. Cependant, la plupart des classes permettant d’interagir avec le système de fichiers demandent à utiliser un type un peu plus adapté ; ce genre de stockage est en fait surtout utile quand il s'agit de lire ou d’écrire le chemin vers le fichier ou un répertoire depuis la ligne de commande, un champ de saisie dans une interface graphique, un fichier de configuration, les préférences utilisateur ou encore dans une base de données.
Code Java : | Sélectionner tout |
1 2 | String fichier1 = "/home/jean/.bashrc"; String fichier2 = "c:\\users\\alexandra\\Documents\\lettre.docx"; |
API Java classique
Il est possible de référencer un fichier ou un répertoire en utilisant la classe java.io.File.
Code Java : | Sélectionner tout |
1 2 | File fichier1 = new File("/home/jean/.bashrc"); File fichier2 = new File("c:\\users\\alexandra\\Documents\\lettre.docx"); |
La méthode toPath() de la classe File permet de convertir une instance de File en une instance de Path.
NIO2
Il est possible de référencer un fichier ou un répertoire en utilisant la classe java.nio.file.Path. Il est possible de construire une instance de cette classe en utilisant la classe utilitaire java.nio.file.Paths :
Code Java : | Sélectionner tout |
1 2 | Path fichier1 = Paths.get("/home/jean/.bashrc"); Path fichier2 = Paths.get("c:\\users\\alexandra\\Documents\\lettre.docx"); |
La méthode toFile() de la classe Path permet de convertir une instance de Path en une instance de File.
URI et URL
Certaines parties de l'API qui fonctionnent avec des ressources réseau ou localisées dans des archives peuvent également fonctionner avec des ressources locales du système de fichiers définies dans des objets de type java.net.URL ou java.net.URI :
Code Java : | Sélectionner tout |
1 2 3 4 5 | File fichier = [...] URI uri = fichier.toURI(); URL url = fichier.toURI().toURL(); // Déprécié dans les JDK récents. // URL url = fichier.toURL(); |
Ou :
Code Java : | Sélectionner tout |
1 2 3 | Path fichier = [...] URI uri = fichier.toUri(); URL url = fichier.toUri().toURL(); |
API Java classique
Vous pouvez invoquer la méthode length() de la classe java.io.File :
Code Java : | Sélectionner tout |
1 2 | File fichier = [...] long taille = fichier.length(); |
La valeur retournée est un long contenant le nombre d'octets du fichier. De manière générale, la taille retournée par les répertoires n'est pas définie et les pseudofichiers système retourneront une taille de 0L.
NIO2
Vous pouvez invoquer la méthode statique size() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
1 2 | Path fichier = [...] long taille = Files.size(fichier); |
La valeur retournée est un long contenant le nombre d'octets du fichier. De manière générale, la taille retournée par les répertoires n'est pas définie et les pseudofichiers système retourneront une taille de 0L. Cette méthode peut générer une exception de type IOException en cas d'erreur.
API Java classique
Aucune solution n'est disponible pour connaître la date de création d'un fichier. En effet, certains systèmes comme UNIX ne fournissant pas cette information, aucune solution portable n'existe. Pour connaître cette information sur les systèmes Windows, il faudra exécuter un appel JNI, JNA ou une commande système.
NIO2
Il est possible de récupérer l'attribut basic:creationTime en invoquant la méthode statique getAttribute() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
1 2 | Path fichier = [...] FileTime dateCreation = (FileTime)Files.getAttribute(fichier, "basic:creationTime", LinkOption.NOFOLLOW_LINKS); |
Cependant, sur les systèmes UNIX, la date renvoyée sera la dernière date de modification du fichier. Sur les systèmes supportant le stockage de la date de création, c'est cette date-ci qui sera renvoyée. Cette méthode retourne un objet de type java.nio.file.attribute.FileTime compatible avec l'API java.time du JDK8. Par défaut, si aucune option java.nio.file.LinkOption.NOFOLLOW_LINKS n'est spécifiée, cette méthode suit les liens symboliques et retournera la date de création du fichier ciblé. Cette méthode peut générer une exception de type IOException en cas d'erreur.
En revanche, ici, il n'y a aucun problème : cette information est disponible sur tous les systèmes de fichiers.
API Java classique
Il est possible d'invoquer la méthode lastModified() de la classe java.io.File :
Code Java : | Sélectionner tout |
1 2 | File fichier = [...] long dateModification = fichier.lastModified(); |
Toutefois, le long retourné par la méthode lastModified() peut dépendre du système d'exploitation et donc ne pas être toujours extrêmement précis.
NIO2
Il est possible d'invoquer la méthode statique getLastModifiedTime() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
1 2 | Path fichier = [...] FileTime dateModification = Files.getLastModifiedTime(fichier, LinkOption.NOFOLLOW_LINKS); |
Il est également possible d'invoquer la méthode statique getAttribute() de la classe utilitaire java.nio.file.Files en spécifiant l’attribut "basic:lastModifiedTime" :
Code Java : | Sélectionner tout |
1 2 | Path fichier = [...] FileTime dateModification = (FileTime)Files.getAttribute(fichier, "basic:lastModifiedTime", LinkOption.NOFOLLOW_LINKS); |
Ces méthodes retournent un objet de type java.nio.file.attribute.FileTime compatible avec l'API java.time du JDK8. Par défaut, si aucune option java.nio.file.LinkOption.NOFOLLOW_LINKS n'est spécifiée, ces méthodes suivent les liens symboliques et retourneront la date de modification du fichier ciblé. Ces méthodes peuvent générer une exception de type IOException en cas d'erreur.
API Java classique
Pour les JDK les plus anciens, il n'existe aucune solution pleinement portable, donc aucune solution pure Java. À partir du JDK 6, il est possible de connaître simplement l'espace libre, l'espace utilisable et l'espace totale grâce à trois nouvelles méthodes de la classe java.io.File :
- getTotalSpace() - retourne l'espace total du disque physique sur lequel se trouve le fichier ;
- getFreeSpace() - retourne l'espace disponible du disque physique sur lequel se trouve le fichier ;.
- getUsableSpace() - retourne l'espace utilisable du disque physique sur lequel se trouve le fichier.
Code Java : | Sélectionner tout |
1 2 3 4 | File fichier = [...] System.out.println("Espace total : " + fichier.getTotalSpace()); System.out.println("Espace libre : " + fichier.getFreeSpace()); System.out.println("Espace utilisable : " + fichier.getUsableSpace()); |
Les valeurs retournées sont des long indiquant un nombre d'octets.
NIO2
La méthode statique getFileStore() de la classe utilitaire java.nio.file.Files permet de récupérer l'espace de stockage sur lequel se trouve un fichier donné. Il est ensuite possible de récupérer ces informations en accédant à la classe java.nio.file.FileStore qui définit les espaces de stockage sur le système :
- getTotalSpace() - retourne l'espace total de l'espace de stockage ;
- getFreeSpace() - retourne l'espace disponible de l'espace de stockage ;
- getUsableSpace() - retourne l'espace utilisable de l'espace de stockage ;
Code Java : | Sélectionner tout |
1 2 3 4 5 | Path fichier = [...] FileStore stockage = Files.getFileStore(fichier); System.out.println("Espace total : " + stockage.getTotalSpace()); System.out.println("Espace libre : " + stockage.getUnallocatedSpace()); System.out.println("Espace utilisable : " + stockage.getUsableSpace()); |
Les valeurs retournées sont des long indiquant un nombre d'octets. Ces méthodes peuvent lever une exception de type IOException en cas d'erreur.
Note : la méthode getFileStores() de la classe java.nio.file.FileSystem permet de lister tous les espaces de stockage de votre machine.
Code Java : | Sélectionner tout |
1 2 3 | Iterable<FileStore> stockages = FileSystems.getDefault().getFileStores(); // Ou : // Iterable<FileStore> stockages = fichier.getFileSystem().getFileStores(); |
Les éléments racines d'un système de fichiers permettent de construire les chemins vers des fichiers, des répertoires ou des ressources. Sous Windows, les racines sont les différents lecteurs logiques (A:\, C:\, D:\, etc. ) ; tandis que, sous Unix, il existe une seule et unique racine système : /.
API Java classique
La classe java.io.File fournit la méthode statique listRoots() à cet effet :
Code Java : | Sélectionner tout |
File[] listeRacine = File.listRoots();
NIO2
La classe java.nio.file.FileSystem fournit la méthode getRootDirectories() à cet effet. Il est possible d'obtenir une référence sur le système de fichiers courant en invoquant la méthode statique getDefault() de la classe utilitaire java.nio.file.FileSystems :
Code Java : | Sélectionner tout |
Iterable<Path> listeRacine = FileSystems.getDefault().getRootDirectories();
Les différents systèmes d'exploitation ne gèrent pas les arborescences de fichiers de la même façon. Le monde Windows associe les périphériques physiques à des lettres de lecteur, le monde Unix utilise un seul répertoire racine. De plus, les séparateurs de fichiers ne sont pas les mêmes (respectivement '\' et '/'). Tout ceci doit être analysé afin d'assurer la portabilité de l'application ; heureusement Java fournit tous les outils pour localiser efficacement les fichiers en gardant toute l'indépendance vis-à-vis du système d'exploitation.
Le plus important est de ne jamais utiliser directement de séparateur de fichiers, mais d'utiliser les constantes définies en fonction du système dans la classe java.io.File :
- File.separatorChar - le char à utiliser pour séparer des noms de répertoires dans l'arborescence d'un chemin définissant un nom de fichier ;
- File.separator - même chose stockée dans une instance de la classe String ;
- File.pathSeparatorChar - le char à utiliser lorsqu'on manipule des listes de fichiers ; par exemple dans des variables environnement système ;
- File.pathSeparator - même chose stockée dans une instance de la classe String.
Pour distinguer un fichier, d'un répertoire ou d'un lien :
API Java classique
Il est possible d'invoquer les méthodes isDirectory() et isFile() de la classe java.io.File pour tester si on manipule un fichier ou un répertoire :
- isDirectory() - retourne true si le chemin testé dénote un répertoire ;
- isFile() - retourne true si le chemin testé dénote un simple fichier ;
Code Java : | Sélectionner tout |
1 2 | boolean estUnRepertoire = monFichier.isDirectory(); boolean estUnFichier = monFichier.isFile(); |
Tester si un chemin dénote un lien dans l'API standard est moins aisé : vous devez tester si le nom absolu du fichier est différent de son nom canonique :
Code Java : | Sélectionner tout |
boolean estUnLien = !monFichier.getAbsolutePath().equals(monFichier.getCanonicalPath();
Cependant cette méthode n'est pas sûre a 100 %. L'API Apache commons, teste quant à elle, les noms absolus et canoniques du parent du fichier plutôt que du fichier lui-même, mais cela a tendance à ne pas fonctionner sur les plateformes Windows.
NIO2
Il est possible d'invoquer les méthodes isRegularFile(), isDirectory() et isSymbolicLink() de la classe utilitaire java.nio.file.Files pour tester si on manipule un fichier, un répertoire ou un lien symbolique :
- isDirectory() - retourne true si le chemin testé dénote un répertoire ;
- isRegularFile() - retourne true si le chemin testé dénote un simple fichier.
- isSymbolicLink() - retourne true si le chemin testé dénote un lien symbolique.
Code Java : | Sélectionner tout |
1 2 3 | boolean estUnRepertoire = Files.isDirectory(monFichier); boolean estUnFichier = Files.isRegularFile(monFichier.); boolean estUnLien = Files.isSymbolicLink(monFichier.); |
Il est assez classique de vouloir lister le contenu d'un répertoire pour connaître tous les fichiers et les sous-répertoires qu'il contient.
API Java classique
Pour obtenir la liste des fichiers et sous-répertoires d'un répertoire, vous devez invoquer la méthode listFile() de la classe java.io.File pour lister tous les fichiers et sous-répertoires qu'il contient :
Code Java : | Sélectionner tout |
File[] fichiers = repertoire.listFiles();
Il est également possible d'invoquer la méthode list() pour obtenir le nom des fichiers et des sous-fichiers contenus dans ce répertoire :
Code Java : | Sélectionner tout |
String[] nomFichiers = repertoire.list();
Ces méthodes sont bloquantes et retournent après que le contenu a été intégralement chargé dans le tableau résultat. Leur invocation peut donc être longue dans un répertoire contenant de très nombreux fichiers et sous-répertoires.
Les méthodes list() et listFiles() peuvent accepter en paramètre une instance de l'interface java.io.FilenameFilter qui permet de filtrer le contenu du répertoire en testant le nom des fichiers enfants et sous-répertoires. La méthode listFiles() peut également accepter en paramètre une instance de l'interface java.io.FileFilter qui permet de filtrer le contenu du répertoire en testant les fichiers enfants et les sous-répertoires.
Attention : le tableau retourné sera vide si le répertoire est vide ; mais il sera null si repertoire dénote un fichier et non pas un répertoire ou si une erreur est survenue en cours d’opération.
NIO2
Contrairement à l'API classique, les méthodes de NIO2 ne sont pas bloquantes, mais elles demandent un peu plus de code pour être utilisées. Il existe deux manières de procéder en fonction de la version de votre JDK :
JDK7
la méthode statique newDirectoryStream() de la classe utilitaire java.nio.file.Files permet d'obtenir une séquence itérable des fichiers et sous-répertoires du chemin ciblé :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | List<Path> fichiers = new ArrayList<>(); try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(repertoire)) { for (Path path : directoryStream) { fichiers.add(path); } } catch (IOException e) { e.printStackTrace() } |
Ou :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | List<String> nomFichiers = new ArrayList<>(); try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(repertoire)) { for (Path path : directoryStream) { nomFichiers.add(path.getFileName().toString()); } } catch (IOException e) { e.printStackTrace() } |
L'instance de java.nio.file.DirectoryStream<Path> retourné par la méthode newDirectoryStream() est une séquence itérable peuplée de manière lazy (paresseuse), c'est-à-dire que le contenu n'est pas chargé à l’avance en mémoire, mais qu'il est peuplé au fur et à mesure que la séquence est parcourue. Cette méthode génère une exception si le chemin spécifié ne dénote pas un répertoire.
De plus, la méthode newDirectoryStream() permet de spécifier une instance de l'interface java.nio.file.DirectoryStream.Filter<Path> qui permet de filtrer le contenu du répertoire ciblé en testant les fichiers enfants et les sous-répertoires.
JDK8
À partir du JDK8, il est possible d'utiliser les flux de données (data stream) en invoquant la méthode statique list() de la classe utilitaire java.nio.file.Files pour procéder à cette opération :
Code Java : | Sélectionner tout |
Stream<Path> fichiers = Files.list(repertoire);
Ou :
Code Java : | Sélectionner tout |
1 2 | Stream<String> nomFichiers = Files.list(repertoire) .map(path -> path.getFileName().toString()); |
Le stream retourné par la méthode list() repose sur une instance de DirectoryStream<Path> et est donc peuplé de manière paresseuse. Cette méthode génère une exception si le chemin spécifié ne dénote pas un répertoire.
Il est possible de filtrer le flux en invoquant son opération filter() et en lui fournissant une instance de java.util.function.Predicate<Path> comme à l'habitude.
Ces exemples effectuent un parcours récursif d'une arborescence de fichiers et affichent (sur la sortie standard) la liste de tous les fichiers contenus dans le répertoire et ses sous-répertoires.
Attention : ces algorithmes ne fonctionnent pas correctement avec une arborescence cyclique sous UNIX ! Des tests supplémentaires sont requis pour gérer correctement les liens symboliques et permettre ou pas de les suivre.
API Java classique
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static void listeRepertoire ( File repertoire ) { System.out.println ( repertoire.getAbsolutePath()); if (repertoire.exists() && repertoire.isDirectory()) { File[] fichiers = repertoire.listFiles(); if (list != null) { for (File fichier : fichier) { // Appel récursif sur les sous-répertoires listeRepertoire(child); } } else { System.err.println(repertoire + " : Erreur de lecture."); } } } |
NIO2
Il existe deux manières d'effectuer un tel parcours en fonction de votre version du JDK :
JDK7
Il faut utiliser le patron de conception visiteur pour parcourir l'arborescence située sous le répertoire :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public static void listeRepertoire(final Path repertoire) { if (Files.exists(repertoire) && Files.isDirectory(repertoire)) { try { Files.walkFileTree(repertoire, new SimpleFileVisitor<Path>() { // Peut être utilisé pour effectuer des actions sur le répertoire et les sous-répertoires en début de visite. @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println(dir.toString()); return FileVisitResult.CONTINUE; } // Peut être utilisé pour effectuer des actions sur les fichiers dans chaque répertoire au cours de la visite. // @Override // public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // return FileVisitResult.CONTINUE; // } // Peut être utilisé pour effectuer des actions sur le répertoire et les sous-répertoires en fin de visite. // @Override // public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { // return FileVisitResult.CONTINUE; // } }); } catch (IOException e) { System.err.println(repertoire + " : Erreur de lecture."); } } } |
JDK8
À partir du JDK8, il est possible d'utiliser les flux de données (data stream) pour parcourir l’arborescence du répertoire de manière similaire à ce que nous effectuions dans l'API classique :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | public static void listeRepertoire(final Path repertoire) { System.out.println(repertoire.toString()); if (Files.exists(repertoire) && Files.isDirectory(repertoire)) { try { Files.list(repertoire) .filter(fichier -> Files.isDirectory(fichier)) .forEach(MaClasse::listeRepertoire); } catch (IOException e) { System.err.println(repertoire + " : Erreur de lecture."); } } } |
API Java classique
La suppression des fichiers et des répertoires est effectuée grâce à la méthode delete() de la classe java.io.File. Cette méthode renvoie un booléen en résultat indiquant si la suppression a réussi. Les causes possibles d'un échec peuvent être :
- le répertoire n'est pas vide ;
- le fichier est inexistant ;
- le fichier est en lecture seule ;
- le fichier est ouvert par une application ou par le système ;
- un flux ouvert est sur le fichier ;
- etc.
Attention : l'API ne permet pas de supprimer un répertoire contenant des fichiers, il faut donc supprimer à la main tous les fichiers du répertoire avant de tenter de supprimer le répertoire lui-même :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static boolean effacerRepertoire(File repertoire) { if (repertoire.exists() && repertoire.isDirectory()) { boolean resultat = true; File[] fichiers = repertoire.listFiles(); for (File fichier : fichiers) { if (fichier.isDirectory()) { resultat &= effacerRepertoire(fichier); } else { resultat &= fichier.delete(); } } resultat &= repertoire.delete(); return resultat; } return false; } |
NIO2
La suppression des fichiers et des répertoires est effectuée grâce aux méthodes statiques delete() ou deleteIfExists() de la classe utilitaire java.nio.file.Files. Dans le cas où le chemin spécifié dénote un lien symbolique, seul le lien est supprimé, pas sa cible. La méthode delete() génère une exception en cas d’échec tandis que la méthode deleteIfExists() renvoie un booléen en résultat qui indique si la suppression a réussi. Les causes possibles d'un échec peuvent être :
- le répertoire n'est pas vide (génère une exception sur les deux méthodes) ;
- le fichier est inexistant ;
- le fichier est en lecture seule ;
- le fichier est ouvert par une application ou par le système ;
- un flux ouvert est sur le fichier ;
- etc.
Attention : l'API ne permet pas de supprimer un répertoire contenant des fichiers, il faut donc supprimer à la main tous les fichiers du répertoire avant de tenter de supprimer le répertoire lui-même.Il existe deux manières différentes pour procéder en fonction de la version de votre JDK :
JDK7
Il faut utiliser le patron de conception visiteur pour parcourir l'arborescence située sous le répertoire à supprimer pour en effacer le contenu :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public static boolean effacerRepertoire(Path repertoire) { if (Files.exists(repertoire) && Files.isDirectory(repertoire)) { try { Files.walkFileTree(repertoire, new SimpleFileVisitor<Path>() { // On efface les fichiers dans chaque répertoire au cours de la visite. @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } // On efface le répertoire et les sous-répertoires en fin de visite. @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.delete(dir); return FileVisitResult.CONTINUE; } }); return true; } catch (IOException e) { e.printStackTrace(); } } return false; } |
JDK8
À partir du JDK8, il est possible d'utiliser les flux de données (data stream) pour parcourir l’arborescence du répertoire de manière similaire à ce que nous effectuions dans l'API classique :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public static boolean effacerRepertoire(Path repertoire) { try { if (Files.exists(repertoire) && Files.isDirectory(repertoire)) { boolean resultat = Files.list(repertoire) .map(MaClasse::effacerRepertoire) .reduce(true, (a, b) -> a & b); Files.delete(repertoire); return resultat; } } catch (IOException e) { e.printStackTrace(); } return false; } |
API Java classique
La méthode renameTo() de la classe java.io.File permet très facilement de renommer un fichier. De plus, si le répertoire destination est différent du répertoire source, le fichier sera déplacé. Cette méthode renvoie un booléen en résultat indiquant si la suppression a réussi. Les causes possibles d'un échec peuvent être :
- le chemin d’accès vers le fichier destination n'est pas valide ;
- le fichier source est inexistant ;
- le fichier source ou le fichier destination est en lecture seule ;
- le fichier source ou le fichier destination est ouvert par une application ou par le système ;
- un flux ouvert est sur le fichier source ou le fichier destination ;
- etc.
Code Java : | Sélectionner tout |
1 2 3 | File source = new File("mon fichier"); File destination = new File("mon fichier renommé"); boolean resultat = source.renameTo(destination); |
Attention : le déplacement n'est effectué que si la source et la destination sont sur le même disque physique, sinon une copie de fichier est nécessaire.
NIO2
La méthode statique move() de la classe utilitaire java.nio.file.Files permet de déplacer ou de renommer un fichier :
Code Java : | Sélectionner tout |
1 2 3 | Path source = Paths.get("mon fichier"); Path destination = Paths.get("mon fichier renommé"); Files.move(source, destination, StandardCopyOptions.REPLACE_EXISTING); // Écrase le fichier destination s'il existe déjà. |
Cette méthode peut générer une exception de type IOException en cas d'erreur.
Généralement, en fonction des capacités du système de fichiers, cette méthode peut être utilisée pour déplacer un répertoire non vide sur le même disque physique, mais échouera si la destination est située sur un FileStore différent, car cela implique des opérations plus complexes sur les fichiers contenus dans le répertoire.
API Java classique
L'API ne fournissant pas de solution clé en main pour la copie de fichier, voici un bout de code qui devrait fonctionner :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static boolean copier(File source, File dest) { try (InputStream sourceFile = new java.io.FileInputStream(source); OutputStream destinationFile = new FileOutputStream(dest)) { // Lecture par segment de 0.5Mo byte buffer[] = new byte[512 * 1024]; int nbLecture; while ((nbLecture = sourceFile.read(buffer)) != -1){ destinationFile.write(buffer, 0, nbLecture); } } catch (IOException e){ e.printStackTrace(); return false; // Erreur } return true; // Résultat OK } |
NIO
Depuis le JDK 1.4, l'API Java a été enrichie de NIO ; voici le code à utiliser pour une copie plus rapide de fichier en utilisant cette nouvelle API :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | public static boolean copier(File source, final destination) { try (FileChannel in = new FileInputStream("toto.txt").getChannel(); // canal d'entrée FileChannel out = new FileOutputStream("tutu.txt").getChannel()) { // canal de sortie // Copie depuis le in vers le out in.transferTo(0, in.size(), out); } catch (IOException e) { e.printStackTrace(); return false; } return true; } |
NIO2
Depuis le JDK 1.7, il est possible d'utiliser NIO2 pour effectuer cette opération de manière encore plus concise en invoquant une des variantes de la méthode statique copy() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | public static boolean copier(Path source, Path destination) { try { Files.copy(source, destination); // Il est également possible de spécifier des options de copie. // Ici : écrase le fichier destination s'il existe et copie les attributs de la source sur la destination. //Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); } catch (IOException e) { e.printStackTrace(); return false; } return true; } |
Cette variante de la méthode copy() retourne le Path destination en résultat. Les autres variantes de cette méthode retournent un long indiquant le nombre d'octets qui ont été lus ou écrits ce qui permet de vérifier si la source a été intégralement copiée dans la destination.
API Java classique
On a vu que le déplacement d'un fichier pouvait être fait grâce à la méthode renameTo() de la classe java.io.File, mais cette solution n'est valable que pour des déplacements à l'intérieur d'un même disque physique... Nous allons donc utiliser l'algorithme de copie suivant lorsque le renommage ne suffit pas :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static boolean deplacer(File source, File destination) { if (!destination.exists()) { // On essaye avec renameTo() boolean result = source.renameTo(destination); if (!result) { // On essaye de copier. result = true; result &= copier(source, destination); // Puis d'effacer. if (result) { result &= source.delete(); } } return result; } // Si le fichier destination existe, on annule... return false; } |
NIO2
La méthode statique move() de la classe utilitaire java.nio.file.Files peut être utilisée à cet effet.
Note : les méthodes permettant d'obtenir le type MIME d'un fichier en utilisant l'API Java classique ou l'API NIO2 peuvent ne pas retourner le même résultat.
API Java classique
Il n'existe pas de méthode dans l'API classique permettant d’accéder au type MIME en utilisant les classes de gestion de fichiers, mais cette information peut être accessible grâce à la classe URLConnection du package java.net.
Par exemple, en se basant sur la connexion ouverte sur ce fichier :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | File fichier = [...] String typeMime = null; if (fichier.exists() && !fichier.isDirectory()) { try { URL url = fichier.toURI().toURL(); URLConnection connection = url.openConnection(); typeMime = connection.getContentType(); } catch (IOException e) { e.printStackTrace(); } } |
Ou, en se basant sur le nom du fichier :
Code java : | Sélectionner tout |
1 2 3 4 5 | File fichier = [...] String typeMime = null; if (fichier.exists() && !fichier.isDirectory()) { typeMime = URLConnection.guessContentTypeFromName(file.getName()); } |
Ou, en inspectant son entête :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | File fichier = [...] String typeMime = null; if (fichier.exists() && !fichier.isDirectory()) { try (InputStream input = new FileInputStream(fichier)) { typeMime = URLConnection.guessContentTypeFromStream(input); } catch (IOException e) { e.printStackTrace(); } } |
Ici le type MIME retourné repose sur une table de définition interne au JDK et chargée lors de l'initialisation des classes.
NIO2
Il est possible d'invoquer la méthode statique probeContentType() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | Path fichier = [...] String typeMime = null; if (Files.exists(fichier) && !Files.isDirectory(fichier)) { try { Files.probeContentType(fichier); } catch (IOException e) { e.printStackTrace(); } } |
Cette méthode repose sur la configuration de la JVM et il est possible d'activer ou de désactiver des objets de type java.nio.file.spi.FileTypeDetector pour prendre en charge de nouveaux types de fichiers.
Un fichier temporaire est un fichier qui sera créé dans le répertoire temporaire du système :
API Java classique
Vous pouvez invoquer la méthode statique createTempFile() de la classe java.io.File :
Code Java : | Sélectionner tout |
File temp = File.createTempFile("nom",".tmp");
Cette méthode peut générer une exception de type IOException en cas d'erreur.
Il est possible d'invoquer la méthode deleteOnExit() sur l'objet de type File pour que le fichier soit automatiquement supprimé à la fin de l'application (si la JVM quitte correctement).
NIO2
Vous pouvez invoquer la méthode statique createTempFile() de la classe utilitaire java.nio.file.Files :
Code Java : | Sélectionner tout |
Path temp = Files.createTempFile("nom", ".tmp");
Cette méthode peut lever une exception de type IOException en cas d'erreur.
API Java classique
Il n'existe pas de méthode portable pour tester les permissions sur un fichier dans les versions les plus anciennes de la JVM. À partir du JDK 1.6, la classe java.io.File dispose de trois méthodes permettant de récupérer des informations basiques sur le fichier testé :
- canExecute() - renvoie true s'il est possible d’exécuter le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant exécutable dans le système de fichiers ;
- canRead() - renvoie true s'il est possible de lire le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant lisible dans le système de fichiers ;
- canWrite() - renvoie true s'il est possible d’écrire dans le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant modifiable dans le système de fichiers.
Code Java : | Sélectionner tout |
1 2 3 4 | File fichier = [...] System.out.println("Lisible - " + fichier.canRead()); System.out.println("Modifiable - " + fichier.canWrite()); System.out.println("Exécutable - " + fichier.canExecute()); |
NIO2
La classe utilitaire java.nio.file.Files dispose de trois méthodes permettant de récupérer des informations basiques sur le fichier testé :
- isExecutable() - renvoie true s'il est possible d’exécuter le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant exécutable dans le système de fichiers ;
- isReadable() - renvoie true s'il est possible de lire le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant lisible dans le système de fichiers ;
- isWritable() - renvoie true s'il est possible d’écrire dans le fichier. Sur certaines plateformes et en fonction des capacités de la JVM, cette méthode peut retourner true même si le fichier n'est pas marqué comme étant modifiable dans le système de fichiers.
Code Java : | Sélectionner tout |
1 2 3 4 | Path fichier = [...] System.out.println("Lisible - " + Files.isReadable(fichier)); System.out.println("Modifiable - " + Files.isWritable(fichier)); System.out.println("Exécutable - " + Files.isExecutable(fichier)); |
NIO2
Vous pouvez savoir si votre système de fichiers supporte tel type d'attributs ou permet de gérer tel type de permissions en testant les valeurs retournées par la méthode supportedFileAttributeViews() de la classe java.nio.file.FileSystem :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | Path fichier = [...] FileSysteme systemeFichier = fichier.getFileSystem(); boolean supporteBasique = systemeFichier.supportedFileAttributeViews().contains("basic"); // Attributs et permissions basiques. boolean supporteDos = systemeFichier.supportedFileAttributeViews().contains("dos"); // Attributs et permissions DOS. boolean supportePosix = systemeFichier.supportedFileAttributeViews().contains("posix"); // Attributs et permissions POSIX. boolean supporteAcl = systemeFichier.supportedFileAttributeViews().contains("acl"); // Attributs et permissions ACL. boolean supporteProprietaire = systemeFichier.supportedFileAttributeViews().contains("owner"); // Attributs et permissions propriétaire. boolean supporteUtilisateur = systemeFichier.supportedFileAttributeViews().contains("user"); // Attributs et permissions définis par l’utilisateur. |
NIO2
Il est possible d'invoquer la méthode statique readAttributes() de la classe utilitaire java.nio.file.Files pour obtenir les attributs d'un fichier :
Code Java : | Sélectionner tout |
1 2 3 4 | Path ficher = [...] Map<String, Object> attributs = Files.readAttributes(ficher, "basic:*", LinkOption.NOFOLLOW_LINKS); // Ou: BasicFileAttributes attributs = Files.readAttributes(ficher, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); |
Lors de l'invocation de la première méthode, il est possible de spécifier le nom d'un attribut particulier à récupérer ou « * » pour récupérer l'ensemble des attributs. Lors de l'invocation de la seconde méthode, l'objet retourné est de même type que la classe passée en paramètre de la méthode ; cet objet permet de manipuler directement tous les attributs publics.
Il est également possible d'invoquer la méthode statique getAttribute() de la classe utilitaire java.nio.file.Files en spécifiant un nom d'attribut en particulier :
Code Java : | Sélectionner tout |
long size = (Long) Files.getAttribute(ficher, "basic:size", LinkOption.NOFOLLOW_LINKS);
Par défaut, si aucune option java.nio.file.LinkOption.NOFOLLOW_LINKS n'est spécifiée, ces méthodes suivent les liens symboliques et retourneront les attributs du fichier ciblé. Ces méthodes peuvent générer une exception de type IOException en cas d'erreur et une exception de type UnsupportedOperationException si vous tentez d’accéder à un type d'attributs non supporté par votre système de fichiers.
Les types d'attributs suivants peuvent être utilisés dans la requête :
- "basic:" ou java.nio.file.attribute.BasicFileAttributes - attributs basiques communs à tous les systèmes de fichiers :
- "lastModifiedTime" - date de dernière modification (java.nio.file.attribute.FileTime),
- "lastAccessTime" - date de dernier accès (java.nio.file.attribute.FileTime),
- "creationTime" - date de création (java.nio.file.attribute.FileTime),
- "size" - taille (Long),
- "isRegularFile" - si le chemin dénote un simple fichier (Boolean),
- "isDirectory" - si le chemin dénote un répertoire (Boolean),
- "isSymbolicLink" - Si le chemin dénote un lien symbolique (Boolean),
- "isOther" - si le chemin dénote un pseudofichier (Boolean),
- "fileKey" - un identifiant unique pour le fichier, null si non supporté (Object) ;
- "dos:" ou java.nio.file.attribute.DosFileAttributes - attributs des systèmes de fichiers Microsoft (SMB, FAT, NTFS, etc.) :
- "readonly" - si le fichier est en lecture seule (Boolean),
- "hidden" - si le fichier est caché (Boolean),
- "system" - si le fichier est un fichier système (Boolean),
- "archive" - si le fichier est un fichier archive (Boolean) ;
- "posix:" ou java.nio.file.attribute.PosixFileAttributes - Attributs des systèmes de fichiers POSIX (UNIX, etc.) :
- "owner" - le propriétaire POSIX du fichier (java.nio.file.attribute.UserPrincipal),
- "permissions" - les permissions POSIX du fichier (Set<java.nio.file.attribute.PosixFilePermission>),
- "group" - le groupe POSIX auquel appartient le fichier (java.nio.file.attribute.GroupPrincipal) ;
- "acl:" - attributs des systèmes de fichiers supportant une ACL (Access Control List ou "liste de contrôle d’accès") :
- "owner" - le propriétaire ACL du fichier (java.nio.file.attribute.UserPrincipal),
- "acl" - les permissions ACL du fichier (List<java.nio.file.attribute.AclEntry>) ;
- "owner:" - attributs des systèmes de fichiers stockant le propriétaire du fichier :
- "owner" - le propriétaire du fichier (java.nio.file.attribute.UserPrincipal) ;
- "owner" - le propriétaire du fichier (java.nio.file.attribute.UserPrincipal) ;
- "user:" - attributs des systèmes de fichiers supportant des métadonnées définies par l'utilisateur (ex. : sous Solaris). Les champs disponibles dépendent du système de fichiers.
NIO2
Si vous savez que votre système de fichiers permet de modifier un certain type de permissions, vous pouvez alors récupérer une « vue » qui permet d'interagir avec ces permissions et de les modifier ainsi que les attributs du fichier ciblé.
Le code suivant va tenter de modifier les dates de création, modification et du dernier accès ainsi que le groupe et le propriétaire du fichier ciblé sur les systèmes de fichiers compatibles POSIX :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Path fichier = [...] FileSysteme systemeFichier = fichier.getFileSystem(); if (systemeFichier.supportedFileAttributeViews().contains("posix")) { PosixFileAttributeView permissions = Files.getFileAttributeView(fichier, PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); // Changement des dates du fichier FileTime maintenant = FileTime.fromMillis(System.currentTimeMillis()); permissions.setTimes(maintenant, maintenant, maintenant); // Changement de groupe. GroupPrincipal groupe = systemeFichier.getUserPrincipalLookupService().lookupPrincipalByGroupName("projet1"); permissions.setGroup(groupe); // Changement de propriétaire. UserPrincipal utilisateur = systemeFichier.getUserPrincipalLookupService().lookupPrincipalByName("henrid"); permissions.setOwner(utilisateur); } |
Le code suivant ajoute une nouvelle entrée dans la liste des utilisateurs capables de lire un fichier et ses attributs sur les systèmes de fichiers supportant une ACL (Access Control List ou "liste de contrôle d’accès") :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Path fichier = [...] FileSysteme systemeFichier = fichier.getFileSystem(); if (systemeFichier.supportedFileAttributeViews().contains("acl")) { AclFileAttributeView permissions = Files.getFileAttributeView(fichier, AclFileAttributeView.class, LinkOption.NOFOLLOW_LINKS); UserPrincipal utilisateur = systemeFichier.getUserPrincipalLookupService().lookupPrincipalByName("karineb"); AclEntry entry = AclEntry.newBuilder() .setType(AclEntryType.ALLOW) .setPrincipal(utilisateur) .setPermissions(AclEntryPermission.READ_DATA, AclEntryPermission.READ_ATTRIBUTES) .build(); // On récupère la liste de contrôle actuelle. List<AclEntry> acl = permissions.getAcl(); // On ajoute la nouvelle permission dans la liste de contrôle. acl.add(0, entry); // On écrit la liste de contrôle. permissions.setAcl(acl); } |
Évidemment, ces bouts de code ne fonctionneront pas si l'utilisateur qui lance le programme n'a pas les droits de modifier le fichier ciblé ou le pouvoir de lui affecter un autre propriétaire (en général, seul l'administrateur le peut), ou si l'utilisateur ou le groupe ciblé n'existe pas sur le système, etc.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.