par , 22/05/2016 à 10h56 (1253 Affichages)
Il est parfois utile que notre application JavaFx puisse surveiller la suppression, modification ou l’ajout de nouveau fichiers dans un répertoire.
Pour cela on a les API nio avec les classes java.nio.file.WatchEvent, java.nio.file.WatchKey, java.nio.file.WatchService, java.nio.file.FileSystems, java.nio.file.Path et java.nio.file.Paths, oui cela fait beaucoup de classes, mais assez facile a mettre en œuvre.
La plus grande difficulté est que l’appel à la méthode take de la classe watchService est bloquant et cela va beaucoup nous gêner dans l’exécution de notre application JavaFx qui se verra figé lors de l’appel à cette méthode.
On va donc utiliser une classe ScheduledService et une classe Task pour permettre d’exécuter la surveillance du dossier dans un autre Thread que le Thread principal de notre application.
Ci dessous un exemple d’une simple application qui va surveiller le dossier « c:/temp » et va afficher dans une simple ListView les événements.
Fichier FXML : FXMLDocument.fxml
Ce fichier présente une fenêtre avec deux éléments, une ListView dont le fx:id est lstFichier qui permettra l’affichage des événements et un bouton simple qui permettra de fermer l’application dont le fx:id est btnClose.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="331.0" prefWidth="425.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxwatcher.FXMLDocumentController">
<children>
<Button fx:id="btnClose" layoutX="360.0" layoutY="281.0" onAction="#hbtnClose" text="Close" />
<ListView fx:id="lstFichier" editable="true" layoutX="14.0" layoutY="14.0" prefHeight="292.0" prefWidth="329.0" />
</children>
</AnchorPane> |
Classe principale : JavaFXWatcher.java
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
|
package javafxwatcher;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXWatcher extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
} |
Fichier controleur : FXMLDocumentController.java
Le contrôleur va permettre dans la méthode « initialize » de mettre en place un watcher qui va surveiller le dossier « c:/temp ». Et une tâche planifié (Thread) qui sera déclenché toutes les 5 secondes et lit les événements déclenchés (méthode processEvents). La méthode « processEvents » permet le lire les événements du watcher et injecter ces événements dans l’observableList de la ListView.
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| package javafxwatcher;
import java.io.IOException;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.util.Duration;
/**
*
* @author tondeur-h
*/
public class FXMLDocumentController implements Initializable {
@FXML
private Button btnClose;
@FXML
private ListView<String> lstFichier;
ObservableList<String> obliste=FXCollections.observableArrayList();
WatchService ws;
Path dir;
WatchKey keys ;
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>)event;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
lstFichier.setItems(obliste);
//surveiller un répertoire
try {
ws=FileSystems.getDefault().newWatchService();
dir= Paths.get("c:/temp");
keys = dir.register(ws, ENTRY_CREATE, ENTRY_DELETE,ENTRY_MODIFY);
}
catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
// tache planifiée
ScheduledService<Integer> srv=new ScheduledService<Integer>() {
@Override
protected Task<Integer> createTask() {
return new Task<Integer>() {
@Override
protected Integer call() throws Exception {
processEvents();
return null;
}
};
}
};
srv.setDelay(Duration.seconds(5));
srv.setPeriod(Duration.seconds(5));
srv.start();
}
@FXML
private void hbtnClose(ActionEvent event) {
System.exit(0);
}
void processEvents() {
// en attente d'un clé signalée
WatchKey key;
try {
key = ws.take();
} catch (InterruptedException x) {
return;
}
//type d'événement
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
// TBD - provide example of how OVERFLOW event is handled
if (kind == OVERFLOW) {
continue;
}
//Context for directory entry event is the file name of entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
// afficher lévénement
obliste.add(event.kind().name()+" "+child);
}
//reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
}
} |
FIN