"Input/Ouput, 16 ans après" à Devoxx France 2012

583 views

Published on

Ma présentation "Input/Ouput, 16 ans après" a Devoxx France 2012

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
583
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
13
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

"Input/Ouput, 16 ans après" à Devoxx France 2012

  1. 1. 1
  2. 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. 3. Speaker http://www.jmdoudoux.fr @jmdoudouxAuteur de 2 didacticielssous 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. 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
  5. 5. Les entrées / sorties avec Java 5
  6. 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. 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. 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. 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. 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
  11. 11. NIO 2 11
  12. 12. NIO 2Inclus dans Java SE 7JSR 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. 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
  14. 14. L’API FileSystem 14
  15. 15. Les chemins 15
  16. 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. 17. Obtenir une instance de type PathPaths.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. 18. Path : gérer les élémentsMé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
  19. 19. Path : gérer les éléments toString() = C:UsersjmAppDataLocalTempmonfichier.txt getFileName() = monfichier.txt getRoot() = C: getName(0) = Users getNameCount() = 6 getParent() = C:UsersjmAppDataLocalTemp subpath(0,3) = UsersjmAppData toString() = jmAppDataLocalTempmonfichier.txt getFileName() = monfichier.txt getRoot() = null getName(0) = jm getNameCount() = 5 getParent() = jmAppDataLocalTemp subpath(0,3) = jmAppDataLocal 19
  20. 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
  21. 21. Manipuler un Pathpath = Paths.get("C:/Users/admin/./../jm/AppData/Local/Temp/./monfichier.txt");System.out.println("normalize() = " + path.normalize());normalize() = C:UsersjmAppDataLocalTempmonfichier.txtPath path = Paths.get("C:/Users/jm/AppData/Local/");Path nouveauPath = path.resolve("Temp/monfichier.txt");System.out.println(nouveauPath);nouveauPath = path.resolve("C:/Temp");System.out.println(nouveauPath);C:UsersjmAppDataLocalTempmonfichier.txtC:Temp 21
  22. 22. Path : comparer des cheminsPlusieurs 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. 23. Path : convertir des cheminsPlusieurs 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. 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
  25. 25. La manipulation des fichierset des répertoires 25
  26. 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
  27. 27. Globfinal Path file1 = Paths.get("C:/java/test/test.java");final Path file2 = Paths.get("C:/java/test/test.txt");final Path file3 = file1.getFileName();String pattern = "glob:**/*.{java,class}";System.out.println("Pattern " + pattern);PathMatcher matcher = FileSystems.getDefault().getPathMatcher(pattern);System.out.println(file1 + " " + matcher.matches(file1));System.out.format("%-22s %bn", file2, matcher.matches(file2));System.out.format("%-22s %bn", file3, matcher.matches(file3));System.out.println("");pattern = "glob:*.java";System.out.println("Pattern " + pattern);matcher = FileSystems.getDefault().getPathMatcher(pattern);System.out.println(file1 + " " + matcher.matches(file1));System.out.format("%-22s %bn", file3, matcher.matches(file3)); 27
  28. 28. La classe Files• Création : createDirectory(), createFile(), createLink(), createSymbolicLink(), createTempFile(), createTempDirectory(), …• Manipulation : delete(), move(), copy(), …• Type d’un élément : isRegularFile(), isDirectory(), probeContentType(), …• Méta-données et permissions : getAttributes(), getPosixFilePermissions(), isReadable(), isWriteable(), size(), getFileAttributeView(), … 28
  29. 29. Copier 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 }Copie d’un répertoire 29
  30. 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. 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. 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
  33. 33. Créer un lien / un lien symboliquePath 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");}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");} 33
  34. 34. Les événementssur un répertoire 34
  35. 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. 36. L’utilisation de WatchServiceMise en œuvre particulière :• Instanciation avec FileSystem.newWatchService()• Enregistrement avec Path.register() (Path implémente Watchable)• Obtenir et traiter les événements 36
  37. 37. WatchServiceWatchService watcher = FileSystems.getDefault().newWatchService();Path dir = Paths.get("c:/java/test");WatchKey key = dir.register(watcher, ENTRY_CREATE)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();} 37
  38. 38. Les méta-données 38
  39. 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. 40. Les attributs DOSPath 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. 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
  42. 42. Les attributs PosixPath fichier = Paths.get("/home/jm/test.txt");PosixFileAttributes attrs = Files.readAttributes(fichier, PosixFileAttributes.class);UserPrincipal owner = attrs.owner();GroupPrincipal group = attrs.group();System.out.println(owner);System.out.println(group);Path fichier = Paths.get("/home/jm/test.txt");Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-rw-rw-");FileAttribute<Set<PosixFilePermission>> attr =PosixFilePermissions.asFileAttribute(perms);Files.createFile(fichier, attr); 42
  43. 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
  44. 44. Les différentes vuesAttributeView FileAttributeView BasicFileAttributeView DosFileAttributeView PosixFileAttributeView FileOwnerAttributeView AclFileAttributeView PosixFileAttributeView UserDefinedFileAttributeView FileStoreAttributeView 44
  45. 45. BasicFileAttributViewPath fichier = Paths.get("c:/java/test.txt");BasicFileAttributeView view = Files.getFileAttributeView(fichier, BasicFileAttributeView.class);BasicFileAttributes attributes = view.readAttributes();FileTime creationTime = attributes.creationTime();FileTime lastAccessTime = attributes.lastAccessTime();boolean isRegularFile = attributes.isRegularFile(); 45
  46. 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. 47. FileStorefor (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. 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. 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. 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. 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. 52. Afficher un fichier d’un zipPath 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. 53. Extraire et ajouter un fichier à un zipPath 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 larchiveFiles.copy(fs.getPath("/META-INF/MANIFEST.MF"), cible); 53
  54. 54. Parcourir le contenu d’un répertoire DirectoryStream et WalkFileTree 54
  55. 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
  56. 56. DirectoryStreamPath dir = Paths.get("C:/java/projets");try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.java")) { for (Path entry : stream) { System.out.println(entry.getFileName()); }} 56
  57. 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. 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. 59. WalkFileTreePath 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
  60. 60. Lectures / écrituresMises à jour de l’API 60
  61. 61. Gestion des IO avec Java IO NIO NIO 2Java 1.0 Java 1.4 (JSR 51) Java 7 (JSR 203)Synchrone Synchrone ASynchroneBloquant Non bloquant Non bloquantFile FileChannel PathInputStream SocketChannel AsynchronousFileChannelOutputStream ServerSocketChannel AsynchronousByteChannelReader (Charset, Selector, AsynchronousSocketChannelWriter ByteBuffer) AsynchronousServerSocketChannelSocket SeekableByteChannelRandomAccessFile 61
  62. 62. Les méthodes de la classe FilesBesoins Besoinssimples avancés 62
  63. 63. Lire et écrire tout le contenu d’un fichierbyte[] bytes = Files.readAllBytes(path);List<String> lignes = Files.readAllLines(path, Charset.defaultCharset());Files.write(path, bytes);Files.write(path, lignes, Charset.defaultCharset()); 63
  64. 64. Ecrire dans un fichier textefinal Path fichier =Paths.get("c:/java/test/donnees.txt"); final Charset charset = Charset.forName("UTF8"); final String contenu = "Prix 10€"; Files.deleteIfExists(fichier); try (BufferedWriter writer =Files.newBufferedWriter(fichier, charset)) { writer.write(contenu, 0, contenu.length()); } catch (IOException ioe) { // traitement de lerreur }} 64
  65. 65. L’interface SeekableByteChannel • ByteChannel qui gère une position • Channel équivalent à RandomAccessFile • Files.newSeekableByteChannel() • CREATE, CREATE_NEW, READ, WRITE, APPEND, TRUNCATE_EXISTING, NOFOLLOW_LINKS, SYNC, DSYNC, … 65
  66. 66. SeekableByteChannelByteBuffer donneesBonjour =ByteBuffer.wrap("Bonjour".getBytes());ByteBuffer donneesBonsoir =ByteBuffer.wrap("Bonsoir".getBytes());Path path = Paths.get("C:/java/test/fichier.bin");Files.deleteIfExists(path);try (FileChannel fileChannel = FileChannel.open(path,StandardOpenOption.CREATE, StandardOpenOption.WRITE,StandardOpenOption.SYNC)) { fileChannel.position(100); fileChannel.write(donneesBonjour);}try (SeekableByteChannel sbc = Files.newByteChannel(path,StandardOpenOption.WRITE, StandardOpenOption.SYNC)) { sbc.position(200); sbc.write(donneesBonsoir);} 66
  67. 67. Lectures / écritures asynchrones 67
  68. 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. 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. 70. Canaux async : les groupes• Les CompletionHandler sont invoqués par les threads• AsynchronousChannelGroup encapsule un pool de threads• FixedThreadPool• CachedThreadPool 70
  71. 71. Conclusion 71
  72. 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
  73. 73. 73

×