NIO 2

82

description

 

Transcript of NIO 2

Page 1: NIO 2
Page 2: NIO 2

2

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

Qui suis-je ?

Page 3: NIO 2

NIO2

FileSystem API

Lectures/écritures : API mises à jour

Canaux asynchrones (Asynchronous I/0)

Conclusion

3

Plan

Page 4: NIO 2

4

NIO 2

Page 5: NIO 2

5

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

Les défauts de java.io

Page 6: NIO 2

6

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

Les défauts de la classe File

Page 7: NIO 2

7

Spécification JSR 203

JSR 203 : http://www.jcp.org/en/jsr/detail?id=203

Page 8: NIO 2

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

Page 9: NIO 2

9

FileSystem API

Page 10: NIO 2

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)

Page 11: NIO 2

11

L’API FileSystem

Page 12: NIO 2

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

Page 13: NIO 2

13

L’interface Path

Page 14: NIO 2

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

Page 15: NIO 2

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:\\Users\\jm\\AppData\\Local\\Temp\\monfichier.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");

Page 16: NIO 2

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

Page 17: NIO 2

17

L’interface Path : exemple

toString() = C:\Users\jm\AppData\Local\Temp\monfichier.txt

getFileName() = monfichier.txt

getRoot() = C:\

getName(0) = Users

getNameCount() = 6

getParent() = C:\Users\jm\AppData\Local\Temp

subpath(0,3) = Users\jm\AppData

toString() = jm\AppData\Local\Temp\monfichier.txt

getFileName() = monfichier.txt

getRoot() = null

getName(0) = jm

getNameCount() = 5

getParent() = jm\AppData\Local\Temp

subpath(0,3) = jm\AppData\Local

Page 18: NIO 2

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

Page 19: NIO 2

19

L’interface Path : manipuler des chemins

path = Paths.get("C:/Users/admin/

./../jm/AppData/Local/Temp/./monfichier.txt");

System.out.println("normalize() = " + path.normalize());

normalize() = C:\USers\jm\AppData\Local\Temp\monfichier.txt

Path 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:\Users\jm\AppData\Local\Temp\monfichier.txt

C:\Temp

Page 20: NIO 2

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

Page 21: NIO 2

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é

Page 22: NIO 2

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

Page 23: NIO 2

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

Page 24: NIO 2

24

Glob : exemple

Path file1 = Paths.get("c:/test.java");

Path file2 = Paths.get("c:/test.txt");

PathMatcher matcher =

FileSystems.getDefault().getPathMatcher("glob:*.{java,cla

ss}");

matcher.matches(file1);

matcher.matches(file2);

Page 25: NIO 2

25

La manipulation des fichiers et des répertoires

Page 26: NIO 2

26

La classe Files

Ensemble de méthodes statiques

Création : createDirectory(), createFile(), createLink(), createSymbolicLink(), createTempFile(), createTempDirectory(), …

Manipulation : delete(), move(), copy(), …

Type d’élément : isRegularFile(), isDirectory(),…

Méta-Datas et permissions : getAttributes(), getPosixFilePermissions(), isReadable(), isWriteable(), size(), getFileAttributeView(), …

Page 27: NIO 2

27

Exemple : supprimer un fichier (1/2)

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

}

Page 28: NIO 2

28

Exemple : supprimer un fichier (2/2)

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

}

Page 29: NIO 2

29

Exemple : déplacer un fichier

Path source = Paths.get("c:/java/source.txt");

Path cible = Paths.get("c:/temp/cible.txt");

try {

Files.move(source, cible, REPLACE_EXISTING, ATOMIC_MOVE);

// java.lang.UnsupportedOperationException

// Files.move(source, cible, REPLACE_EXISTING,

// COPY_ATTRIBUTES, ATOMIC_MOVE);

} catch(IOException ioe) {

// traitement en cas d’erreur

}

Page 30: NIO 2

30

Exemple : 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

}

Page 31: NIO 2

31

Les liens symboliques

Page 32: NIO 2

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()

Page 33: NIO 2

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");

}

Page 34: NIO 2

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");

}

Page 35: NIO 2

35

L’interface WatchService

Page 36: NIO 2

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

Page 37: NIO 2

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)

Page 38: NIO 2

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();

}

Page 39: NIO 2

39

Les méta-données

Page 40: NIO 2

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

Page 41: NIO 2

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());

Page 42: NIO 2

42

Les attributs Posix

Path 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);

Page 43: NIO 2

43

La gestion des droits Posix

Énumération PosixFilePermission

PosixFilePermissions : helper

FileAttribute : encapsule les attributs

Attention aux restrictions de droits via umask ou via le répertoire parent

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);

Page 44: NIO 2

44

Les attributs via les vues

Les vues permettent d’obtenir les attributs en bloc

Les vues sont spécialisées

Readonly ou mutable

Page 45: NIO 2

45

Les attributs via les vues

AttributeView

FileAttributeView

BasicFileAttributeView

DosFileAttributeView

PosixFileAttributeView

FileOwnerAttributeView

AclFileAttributeView

PosixFileAttributeView

UserDefinedFileAttributeView

FileStoreAttributeView

Page 46: NIO 2

46

Exemple avec BasicFileAttributView

Path 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();

Page 47: NIO 2

47

La classe FileStore

Page 48: NIO 2

48

La classe FileStore

Encapsule un système de stockage : un disque dur, une partition, …

Obtenir des informations

FileStore Files.getFileStore(Path)

Page 49: NIO 2

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 ");

Page 50: NIO 2

50

La classe FileSystem

Page 51: NIO 2

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();

Page 52: NIO 2

52

Le séparateur du système de fichiers

String separateur = File.separator;

String separateur = FileSystems.getDefault().getSeparator();

Page 53: NIO 2

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

Page 54: NIO 2

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

Page 55: NIO 2

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);

}

}

Page 56: NIO 2

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);

Page 57: NIO 2

57

L’interface DirectoryStream

Page 58: NIO 2

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

Page 59: NIO 2

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());

}

}

Page 60: NIO 2

60

WalkFileTree

Page 61: NIO 2

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

Page 62: NIO 2

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;

}

});

Page 63: NIO 2

63

Lectures / écritures

Mises à jour de l’API

Page 64: NIO 2

64

IO

Java 1.0

Synchrone

Bloquant

File InputStream OutputStream Reader Writer Socket RandomAccessFile

La gestion des io avec Java

NIO

Java 1.4 (JSR 51)

Synchrone

Non bloquant

FileChannel SocketChannel ServerSocketChannel (Charset, Selector, ByteBuffer)

NIO 2

Java 7 (JSR 203)

ASynchrone

Non bloquant

Path

AsynchronousFileChannel AsynchronousByteChannel AsynchronousSocketChannel AsynchronousServerSocketChannel

Page 65: NIO 2

65

Obtenir des flux

Path path = Paths.get("c:/java/source.txt");

BufferedReader reader = Files.newBufferedReader(path,

Charset.defaultCharset());

BufferedWriter writer = Files.newBufferedWriter(path,

Charset.defaultCharset());

InputStream inputStream = Files.newInputStream(path);

OutputStream outputStream = Files.newOutputStream(path);

ByteChannel channel = Files.newByteChannel(path);

Page 66: NIO 2

66

L’utilisation des méthodes

Page 67: NIO 2

67

Lire et écrire tout le contenu

byte[] bytes = Files.readAllBytes(path);

List<String> lignes = Files.readAllLines(path,

Charset.defaultCharset());

Files.write(path, bytes);

Files.write(path, lignes, Charset.defaultCharset());

Page 68: NIO 2

68

Exemple : écriture dans un fichier texte

Path file = Paths.get("c:/java/test/test.txt");

Charset charset = Charset.forName("UTF8");

String contenu = "Prix 10€";

try (BufferedWriter writer = Files.newBufferedWriter(file,

charset)) {

writer.write(contenu, 0, contenu.length());

} catch (IOException ioe) {

// traitement de l'erreur

}

Page 69: NIO 2

69

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...

Page 70: NIO 2

70

L’interface SeekableByteChannel : exemple

ByteBuffer donneesBonjour = ByteBuffer.wrap("Bonjour".getBytes());

ByteBuffer donneesBonsoir = ByteBuffer.wrap("Bonsoir".getBytes());

Path path = Paths.get("C:/java/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);

}

Page 71: NIO 2

71

Canaux asynchrones

(Asynchronous I/0)

Page 72: NIO 2

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

Page 73: NIO 2

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

Page 74: NIO 2

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

Page 75: NIO 2

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);

}

Page 76: NIO 2

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());

}

Page 77: NIO 2

77

Les groupes

Les callbacks CompletionHandler sont invoqués par des threads

AsynchronousChannelGroup qui encapsule un pool de threads

DefaultThreadPool

FixedThreadPool

CachedThreadPool

Page 78: NIO 2

78

Conclusion

Page 79: NIO 2

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

Page 80: NIO 2

80

Questions

Page 81: NIO 2

81

Merci pour votre attention

Page 82: NIO 2

82

Licence

http://creativecommons.org/licenses/by-nc-nd/3.0/deed.fr