2. Qui suis-je ?
Architecte logiciel Java/.Net
Auteur de deux didacticiels diffusés sous la licence GNU
FDL : http://www.jmdoudoux.fr
Développons en Java (2330 pages)
Développons en Java avec Eclipse (600 pages)
Rédacteur pour developpez.com,
Membre du Yajug et du CA du Lorraine Jug
2
3. Plan
NIO2
FileSystem API
Lectures/écritures : API mises à jour
Canaux asynchrones (Asynchronous I/0)
Conclusion
3
5. 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
…
5
6. 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
notamment listFiles()
…
=> besoin d’une nouvelle API
6
8. NIO 2
JSR 203 : ajout de nouvelles API au package NIO
Accès et manipulation du système de fichiers
Mise à jour de l’API existante
Canaux asynchrones (asynchronous channels)
Inclus dans Java SE 7
8
10. FileSystem API
API moderne, complète et extensible
Package java.nio.file et sous packages
Accès et gestion des systèmes de fichiers
(fichiers, répertoires, liens symboliques)
Support des méta-datas
Parcours des répertoires
Extensible pour fournir sa propre
implémentation (sous classe de FileSystem)
10
12. Les principaux nouveaux concepts
Path : encapsule un chemin dans le système de
fichiers
Files : méthodes statiques pour des opérations
sur les fichiers et les répertoires
FileSystem : encapsule un système de fichiers,
fabrique d’objets pour y accéder
FileSystems : fabrique d’instances de FileSystem
FileStore : encapsule le système de stockage
sous jacent
12
14. L’interface Path
Encapsule tout ou partie du chemin d’un
élément du système de fichiers
Dépendant du système de fichier
Le chemin encapsulé existe ou non
Immuable
Chemin encapsulé absolu ou relatif
Pas de gestion des extensions des fichiers
Implémente Iterable et Comparable
14
15. L’interface Path
Création à partir d’un String, URI ou java.io.File
La classe helper Paths
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.t
xt");
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");
15
16. L’interface Path : gérer les éléments du chemin
Nombreuses 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
16
18. L’interface Path : manipuler des chemins
Plusieurs méthodes pour manipuler les chemins
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 fournit
18
20. L’interface Path : comparer des chemins
Plusieurs méthodes pour comparer les chemins
int compareTo(Path other) Compare le chemin
avec celui fourni en paramètre
boolean endsWith(Path other)
boolean endsWith(String other)
Compare la fin du chemin avec celui fourni
boolean startsWith(Path other)
boolean startsWith(String other)
Compare le début du chemin avec celui fourni
20
21. L’interface 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 du chemin notamment en
résolvant les liens symboliques selon les
options fournies. Exception si le fichier n’existe
pas ou s’il ne peut pas être accédé
21
22. L’interface Path : intégration dans l’existant
Path File.toPath()
File Path.toFile()
URI Path.toUri() : retourner le chemin sous la
forme d’une URI
22
23. 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
??? é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
23
32. Les liens symboliques
Support optionnel selon le FS (Unix)
Liens symboliques suivis par défaut avec
quelques exceptions : delete(), move(),
walkFileTree()
Files.isSameFile() permet de vérifier si deux
chemins font référence au même endroit
Files.isSymbolicLink()
Files.readSymbolicLink()
32
33. Exemple : créer un lien
Path lien = Paths.get("C:/java/test/monlien");
Path cible = Paths.get("C:/java/test/monfichier.txt");
Files.createLink(lien, cible);
if (Files.isSameFile(lien, cible)) {
System.out.println("Identique");
} else {
System.out.println("Non identique");
}
33
34. Exemple : créer un lien symbolique
Path lien = Paths.get("/home/jm/monlien");
Path cible = Paths.get("/home/jm/monfichier.txt");
Files.createSymbolicLink(lien, cible);
if (Files.isSameFile(lien, cible)) {
System.out.println("Identique");
} else {
System.out.println("Non identique");
}
34
36. WatchService
Notifications de changements dans un
répertoire
Evite d’avoir à écrire du code de type pooling
sur un répertoire
Abonnement à des événements lors de la
création, modification, suppression de fichiers
36
37. WatchService : enregistrement
Instanciation avec
FileSystem.newWatchService()
Enregistrement avec WatchService.register()
WatchService watcher =
FileSystems.getDefault().newWatchService();
Path dir = Paths.get("c:/java");
WatchKey key = dir.register(watcher, ENTRY_CREATE)
37
38. WatchService : obtenir les événements
for (;;) {
try {
key = watcher.take();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
Path name = (Path) event.context();
System.out.format(event.kind() + " " + "%s created", name);
}
}
key.reset();
}
38
40. Les attributs
Gestion complète des attributs qui sont
dépendantes du système sous jacent
Taille, type d’élément, caché, …
Attributs communs (BasicFileAttributes)
ou attributs spécifiques (DosFileAttributes,
PosixFileAttributes)
Gestion des permissions Posix
Méthodes de la classe Files pour en modifier
un
40
41. Les attributs DOS
Path fichier = Paths.get("c:/java/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());
41
48. La classe FileStore
Encapsule un système de stockage : un disque
dur, une partition, …
Obtenir des informations
FileStore Files.getFileStore(Path)
48
49. La classe FileStore : exemple
Path path = Paths.get("c:/test.txt");
FileStore store = Files.getFileStore(path);
long total = store.getTotalSpace() / (1024 * 1024);
long used = (store.getTotalSpace() –
store.getUnallocatedSpace()) / (1024 * 1024);
Long avail = store.getUsableSpace() / (1024 * 1024);
System.out.println("total "+total+" mb ");
49
51. La classe FileSystem
Encapsule un système de fichiers
Obtenir celui du système par défaut ou
invoquer une fabrique
FileSystem fs = FilesSystems.getDefault();
Utiliser une fabrique pour obtenir une
implémentation spécifique
Fabrique pour des objets de l’API
Extensible : possibilité de créer sa propre
implémentation
class MonFileSystem extends FileSystem();
51
52. Le séparateur du système de fichiers
String separateur = File.separator;
String separateur =
FileSystems.getDefault().getSeparator();
52
53. Les providers de FileSystem
Il est possible d’utiliser ou de créer des
fournisseurs de FileSystem
N’ont pas besoin d’être lié à un « vrai »
système de fichiers
Peut permettre d’offrir différentes vues d’un
système de fichiers (cacher les fichiers
sensibles, accès un lecture seule, …)
java.nio.file.spi
53
54. Un provider FileSystem pour les zip
Permet de traiter le contenu d’un zip comme
un FileSystem
Facilite l’utilisation des archives de type zip
54
55. Exemple : 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);
}
}
55
56. Exemple : extraire un fichier d’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);
56
58. La classe DirectoryStream
Itération sur le contenu d’un répertoire
Performance sur un gros répertoire, consomme
moins de ressources
Possibilité d’appliquer un filtre en utilisant un
glob ou une expression régulière
Invoquer la méthode close() après utilisation
58
59. La classe DirectoryStream : exemple
Path dir = Paths.get("C:/java/projets");
try (DirectoryStream<Path> stream =
Files.newDirectoryStream(dir, "*.java")) {
for (Path entry : stream) {
System.out.println(entry.getFileName());
}
}
59
61. WalkFileTree
Parcourir une arborescence en utilisant le
design pattern visitor (opérations récursives)
Files.walkFileTree()
FileVisitor invoqué sur chaque fichier /
répertoire (pre/post)
SimpleFileVisitor : contrôle du parcours par la
valeur de retour (CONTINUE, PRUNE)
Liens symboliques non suivis par défaut
(FOLLOW_LINKS) : détection des références
circulaires
61
62. WalkFileTree : exemple
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;
}
});
62
72. Canaux asynchrones
Channel avec opérations non bloquantes
(connexion, lecture, écriture)
Exécution des opérations de manière
asynchrone (dans un thread)
Contrôle des opérations après leur initialisation
via deux solutions :
java.util.concurrent.Future
java.nio.channels.CompletionHandler
72
73. Canaux asynchrones avec Future
Utiliser l’objet de type Future pour connaitre le
statut et le résultat de l’opération
Future.get() : obtenir le résultat (bloquant!)
Future.get() : avec un timout
Future.isDone() : l’opération est elle terminée
Future.cancel(boolean) : annuler l’opération
73
74. Canaux asynchrones 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);
}
completed() invoqué en cas de succès
failed() invoqué en cas d’erreur
74
75. Exemple : dupliquer un ficher de manière asynchrone
public static void copierAsync(final AsynchronousFileChannel in,
final AsynchronousFileChannel out) {
final ByteBuffer buffer = ByteBuffer.allocate(16384);
class ReadCompletionHandler implements CompletionHandler<Integer, Integer> {
@Override
public void completed(Integer result, Integer position) {
if (result == -1) {
System.out.println("copie terminee");
return;
}
buffer.flip();
System.out.println("ecriture buffer");
out.write(buffer, position, position + result,
new CompletionHandler<Integer, Integer>() {
@Override
public void completed(Integer result, Integer newPosition) {
buffer.compact();
System.out.println("Lecture buffer");
in.read(buffer, newPosition, newPosition, ReadCompletionHandler.this);
}
75
76. Exemple : dupliquer un ficher de manière asynchrone
@Override
public void failed(Throwable exc, Integer attachment) {
System.out.println(exc);
throw new IOError(exc);
}
});
}
@Override
public void failed(Throwable exc, Integer attachment) {
System.out.println(exc);
throw new IOError(exc);
}
}
System.out.println("Lecture buffer");
in.read(buffer, 0, 0, new ReadCompletionHandler());
}
76
77. Les groupes
Les callbacks CompletionHandler sont
invoqués par des threads
AsynchronousChannelGroup qui encapsule un
pool de threads
DefaultThreadPool
FixedThreadPool
CachedThreadPool
77
79. Conclusion
NIO 2 apporte de nombreuses fonctionnalités attendues
depuis longtemps
Les canaux asynchrones ne sont pas facile à utiliser
mais les serveurs d’applications devraient en tirer partie
Téléchargez le JDK 7 et essayez
79