2. Abstract
• Revue rapide des I/O avec Java
• Vue d’ensemble de l’API NIO2
• Fournie avec Java SE 7
• Pour les développeurs que nous sommes
2
3. Speaker
http://www.jmdoudoux.fr
@jmdoudoux
Auteur de 2 didacticiels
sous licence GNU FDL
Développons en Java (2400 pages)
Développons en Java avec Eclipse (600 pages)
Membre du et du CA du
3
4. Agenda
• Les entrées / sorties avec Java
• NIO 2
• L’API Filesystem
• Lectures / écritures : API mises à jour
• Les E/S asynchrones (Asynchronous I/O)
4
6. L’API java.io
• Depuis Java 1.0
• Flux : octets (Input/OutputStream)
caractères (Reader/Writer)
• Fichiers, In Memory, Pipes, Sérialisation, …
• Filtre, Buffer, … (adaptateur, décorateur)
• La classe File
6
7. Les évolutions de la classe File
Java 1.1 getCanonicalPath()
Java 1.2 getParentFile(), getAbsoluteFile(), getCanonicalFile(),
toURL(), isHidden(), createNewFile(), deleteOnExit(),
listFiles(), setLastModified(), setReadOnly(), listRoots(),
createTempFile(), compareTo()
Java 1.4 création à partir d’une URI, toURI()
Java 6 setWritable(), setReadable(), setExecutable(), canExecute(),
getTotalSpace(), getFreeSpace(), getUsableSpace()
7
8. Les défauts de java.io
• Le manque d’opérations basiques (copie, déplacement de
fichiers, …)
• Ne fonctionne pas de la même manière sur toutes les
plateformes
• Support limité des liens symboliques et des méta-données
• …
8
9. Les défauts de la classe File
• Encapsule le chemin et les opérations
• Gestion de certaines erreurs : certaines méthodes renvoient
un booléen sans lever d’exceptions (delete() par exemple)
• Manque de performance de certaines méthodes
• …
9
10. New IO (NIO)
• Java 1.4
• utilisation de blocs et non de flux
• les canaux et sélecteurs (channels et selectors),
• les tampons (buffers),
• encodage et décodage de caractères (charset)
10
12. NIO 2
Inclus dans Java SE 7
JSR 203 : ajout de fonctionnalités à l’API NIO
• Accès et manipulation du système de fichiers
• Mise à jour de l’API existante
• Canaux asynchrones (asynchronous channels)
• …
12
13. L’API FileSystem
• API moderne et complète
• Accès et gestion des systèmes de fichiers (fichiers,
répertoires, liens symboliques, …)
• Support des méta-datas
• Parcours des répertoires, notifications
• Extensible
13
16. L’interface Path
• Immuable, encapsule tout ou partie du chemin d’un élément
du système de fichiers
• Dépendant du système de fichier
• Chemin encapsulé absolu ou relatif existe ou non
• Pas de gestion des extensions des fichiers
16
17. Obtenir une instance
de type Path
Paths.get("monfichier.txt");
Paths.get("jm/AppData/Local/Temp/monfichier.txt");
Paths.get("C:/Users/jm/AppData/Local/Temp/monfichier.txt");
Paths.get("C:UsersjmAppDataLocalTempmonfichier.txt");
Paths.get(URI
.create("file:///C:/Users/jm/AppData/Local/Temp/monfichier.txt"));
Paths.get(System.getProperty("java.io.tmpdir"), "monfichier.txt");
FileSystems.getDefault().getPath("logs", "access.log");
// Sur Unix
// Path path = Paths.get("/home/jm/temp/monfichier.txt");
17
18. Path : gérer les éléments
Méthodes pour gérer les éléments hiérarchiques du chemin
Path getFileName() nom du dernier élément
Path getParent() chemin parent ou null
Path getRoot() racine du chemin ou null
Path subPath(int, int) sous chemin
Path getName(int) élément à l’index fourni
int getNameCount() nombre d’éléments dans le chemin
18
20. Path : manipuler le chemin
• Path normalize() :
supprime les éléments redondants (par exemple . et ..),
purement syntaxique
• Path resolve(Path) :
combiner deux chemins
• Path relativize(Path) :
chemin relatif entre le chemin et celui fourni
20
22. Path : comparer des chemins
Plusieurs méthodes pour comparer les chemins
• int compareTo(Path other)
• boolean endsWith(Path other)
boolean endsWith(String other)
• boolean startsWith(Path other)
boolean startsWith(String other)
• …
22
23. Path : convertir des chemins
Plusieurs méthodes pour convertir les chemins
• Path toAbsolutePath() :
retourner le chemin absolu du chemin
• Path toRealPath(LinkOption…) :
retourner le chemin physique avec résolution des liens
symboliques selon les options fournies
23
24. Path : intégration dans
l’existant
• Path File.toPath()
• File Path.toFile()
• URI Path.toUri() : retourner le chemin sous la forme d’une
URI
24
26. Glob
• Pattern à appliquer sur un élément du système de fichiers
• Sous ensemble des expressions régulières :
* ** ? [] {}
*.java éléments dont le nom fini par .java
Exemples : ??? éléments dont le nom est composé de trois
alphanumériques
A*.java éléments dont le nom commence par un a et se
termine par .java
*[0-9]* éléments dont le nom contient au moins un
chiffre
*.{htm,html} éléments dont le nom se termine par htm ou html
26
30. Déplacer ou renommer
un fichier
Path source = Paths.get("c:/java/fichier.txt");
Path cible = Paths.get("c:/java/fichier_copie.txt");
try {
Files.copy(source, cible, REPLACE_EXISTING,
COPY_ATTRIBUTES);
// java.lang.UnsupportedOperationException
// Files.move(source, cible, REPLACE_EXISTING,
// COPY_ATTRIBUTES, ATOMIC_MOVE);
} catch(IOException ioe) {
// traitement en cas d’erreur
}
Déplacement d’un répertoire
30
31. Supprimer un fichier
Path path = Paths.get("C:/java/test/monfichier_copie.txt");
try {
Files.delete(path);
} catch (NoSuchFileException nsfee) {
// traitement en cas d’erreur
} catch (DirectoryNotEmptyException dnee) {
// traitement en cas d’erreur
} catch (IOException ioe) {
// traitement en cas d’erreur
}
Path path = Paths.get("C:/java/test/monfichier_copie.txt");
try {
Files.deleteIfExists(path);
} catch (DirectoryNotEmptyException dnee) {
// traitement en cas d’erreur
} catch (IOException ioe) {
// traitement en cas d’erreur
}
Suppression d’un répertoire vide
31
32. Les liens symboliques
• Support optionnel selon le FS (Unix)
• Suivis par défaut avec quelques exceptions :
delete(), move(), walkFileTree()
• Files.isSameFile()
• Files.isSymbolicLink()
• Files.readSymbolicLink()
32
35. L’interface WatchService
• Notifications de changements dans un répertoire
• Abonnement à des événements lors de la création,
modification, suppression de fichiers
• Evite d’avoir à écrire du code de type pooling ou une API
open source (JNotify ou JPathWatch)
• Non récursif, performant
35
36. L’utilisation de WatchService
Mise en œuvre particulière :
• Instanciation avec FileSystem.newWatchService()
• Enregistrement avec Path.register()
(Path implémente Watchable)
• Obtenir et traiter les événements
36
39. Les attributs
• Gestion complète des attributs qui sont dépendants du
système sous jacent
• Taille, type d’éléments, caché, …
• Attributs communs (BasicFileAttributes) et spécifiques
(DosFileAttributes, PosixFileAttributes)
• Méthodes de la classe Files
39
40. Les attributs DOS
Path fichier = Paths.get("c:/java/test/test.txt");
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(fichier, now);
Files.setAttribute(fichier, "dos:hidden", true);
DosFileAttributes attr = Files.readAttributes(fichier, DosFileAttributes.class);
System.out.println(attr.isReadOnly());
System.out.println(attr.isHidden());
System.out.println(attr.isRegularFile());
System.out.println(attr.isSystem());
System.out.println(attr.lastModifiedTime());
40
41. Les attributs Posix
• Énumération PosixFilePermission
• PosixFilePermissions : helper
• FileAttribute : encapsule les attributs
Attention aux restrictions de droits via umask
ou via le répertoire parent
41
43. Les attributs avec les vues
• Les vues permettent d’obtenir les attributs d’un même
groupe en bloc -> performance
• Les vues sont spécialisées
• Readonly ou mutable
• Création possible de vues personnalisées
43
46. La classe FileStore
• Encapsule un système de stockage : un disque dur, une
partition, …
• Obtenir des informations
• Connaître les AttributViews supportées
• FileStore Files.getFileStore(Path)
46
47. FileStore
for (final FileStore store : FileSystems.getDefault().getFileStores()) {
System.out.println(store);
System.out.println("nom : " + store.name() + ", type : " + fileStore.type());
System.out.println("Support BasicFileAttribute : "
+ store.supportsFileAttributeView(BasicFileAttributeView.class));
System.out.println("Support DosFileAttribute : "
+ store.supportsFileAttributeView(DosFileAttributeView.class));
System.out.println("Support PosixFileAttribute : "
+ store.supportsFileAttributeView(PosixFileAttributeView.class));
}
final int UN_GIGA = 1024 * 1024 * 1024;
for (final FileStore store : FileSystems.getDefault().getFileStores()) {
try {
final long total = store.getTotalSpace() / UN_GIGA;
final long used = (store.getTotalSpace() - store.getUnallocatedSpace())
/ UN_GIGA;
final long avail = store.getUsableSpace() / UN_GIGA;
System.out.format("%-20s total=%5dGo used=%5dGo avail=%5dGo%n",
store, total, used, avail);
} catch (final IOException e) {
e.printStackTrace();
}
}
47
48. La classe FileSystem
• Encapsule un système de fichiers
• Fabrique pour des objets de l’API
• Obtenir l’instance du système par défaut
FileSystem fs = FilesSystems.getDefault();
48
49. La classe FileSystem
• Extensible
• Peut permettre d’offrir différentes vues d’un système de
fichiers
(cacher des fichiers sensibles, accès en lecture seule, …)
• N’a pas besoin d’être lié à un « vrai » système de fichiers
49
50. Les providers de FileSystem
• Invoquer une fabrique (FileSystems) pour obtenir une
implémentation spécifique
• Utiliser ou de créer des fournisseurs de FileSystem
class MonFileSystem extends FileSystem;
• java.nio.file.spi.FileSystemProvider
50
51. Un provider pour les zip
• Permet de traiter le contenu d’un zip comme un système de
fichiers
• Facilite l’utilisation des archives de type zip
• Fourni en standard
51
52. Afficher un fichier
d’un zip
Path jarfile = Paths.get("c:/java/archive.jar");
FileSystem fs = FileSystems.newFileSystem(jarfile, null);
Path mf = fs.getPath("META-INF", "MANIFEST.MF");
try (BufferedReader readBuffer =
Files.newBufferedReader(mf, Charset.defaultCharset())) {
String ligne = "";
while ((ligne = readBuffer.readLine()) != null) {
System.out.println(ligne);
}
}
52
53. Extraire et ajouter
un fichier à un zip
Path jarfile = Paths.get("c:/java/archive.jar");
FileSystem fs = FileSystems.newFileSystem(jarfile, null);
Path cible = Paths.get("c:/java/MANIFEST.MF");
Files.deleteIfExists(cible);
// extaire un élément de l'archive
Files.copy(fs.getPath("/META-INF/MANIFEST.MF"), cible);
53
55. L’interface DirectoryStream
• Itération sur le contenu d’un répertoire
• Performance sur de gros répertoires, consomme moins de
ressources
• Possibilité d’appliquer un filtre avec un glob
• Invoquer la méthode close() après utilisation
55
57. WalkFileTree avec FileVisitor
• Parcourir une arborescence en utilisant le design pattern
Visiteur (opérations récursives)
• Files.walkFileTree()
• FileVisitor invoqué
sur chaque fichier (visitFile() / visitFileFailed())
sur chaque répertoire (preVisitDirectory()/postVisitDirectory())
57
58. WalkFileTree avec FileVisitor
• SimpleFileVisitor : contrôle du parcours par la valeur de
retour (CONTINUE, SKIP_SUBTREE, TERMINATE, …)
• Liens symboliques non suivis par défaut
(FileVisitOption.FOLLOW_LINKS)
• détection des références circulaires (méthode
visitFileFailed() avec FileSystemLoopException)
58
59. WalkFileTree
Path dir = Paths.get("C:/java/projets");
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
String nom = file.getFileName().toString();
if (nom.endsWith(".java")) {
System.out.println("Fichier : " + nom);
}
return FileVisitResult.CONTINUE;
}
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
System.out.println("Repertoire : " + dir);
return FileVisitResult.CONTINUE;
}
});
59
68. Les canaux asynchrones
• Channel : opérations non bloquantes (lecture, écriture)
• AsynchronousChannel : opérations asynchrones (exécutées
dans un thread)
• Contrôle des opérations après leur initialisation via deux
solutions :
java.util.concurrent.Future
java.nio.channels.CompletionHandler
68
69. Canaux async avec
CompletionHandler
• Callback qui sera invoqué lorsque l’opération se termine
(bien ou mal)
• Paramétré avec le type de résultat et un objet en
attachement (contexte qui peut être null)
interface CompletionHandler<V, A> {
void completed(V result, A attachment);
void failed(Throwable t, A attachment);
}
69
70. Canaux async : les groupes
• Les CompletionHandler sont invoqués par les threads
• AsynchronousChannelGroup encapsule un pool de threads
• FixedThreadPool
• CachedThreadPool
70
72. Conclusion
• NIO2 apporte de nombreuses fonctionnalités, attendues
depuis longtemps
• Implémentation de bas niveau de certaines, mais utilisables
dans différents contextes
• Pour allez plus loin : Javadoc, Java tutorials (Basic I/O),
exemples du JDK (sample/nio/file)
72