Je veux regarder un répertoire pour les changements de fichiers. Et j'ai utilisé WatchService dans Java.nio. Je peux écouter avec succès l'événement créé par le fichier. Mais je ne peux pas écouter l'événement de modification de fichier. J'ai vérifié officiel Java , mais j'ai toujours du mal.
Voici le code source.
import static Java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static Java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static Java.nio.file.StandardWatchEventKinds.OVERFLOW;
import static Java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static Java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import Java.io.File;
import Java.io.IOException;
import Java.nio.file.FileSystem;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.WatchEvent;
import Java.nio.file.WatchEvent.Kind;
import Java.nio.file.WatchKey;
import Java.nio.file.WatchService;
public class MainWatch {
public static void watchDirectoryPath(Path path) {
// Sanity check - Check if path is a folder
try {
Boolean isFolder = (Boolean) Files.getAttribute(path,
"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder) {
throw new IllegalArgumentException("Path: " + path
+ " is not a folder");
}
} catch (IOException ioe) {
// Folder does not exists
ioe.printStackTrace();
}
System.out.println("Watching path: " + path);
// We obtain the file system of the Path
FileSystem fs = path.getFileSystem();
// We create the new WatchService using the new try() block
try (WatchService service = fs.newWatchService()) {
// We register the path to the service
// We watch for creation events
path.register(service, ENTRY_CREATE);
path.register(service, ENTRY_MODIFY);
path.register(service, ENTRY_DELETE);
// Start the infinite polling loop
WatchKey key = null;
while (true) {
key = service.take();
// Dequeueing events
Kind<?> kind = null;
for (WatchEvent<?> watchEvent : key.pollEvents()) {
// Get the type of the event
kind = watchEvent.kind();
if (OVERFLOW == kind) {
continue; // loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
// Output
System.out.println("New path created: " + newPath);
} else if (ENTRY_MODIFY == kind) {
// modified
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
// Output
System.out.println("New path modified: " + newPath);
}
}
if (!key.reset()) {
break; // loop
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public static void main(String[] args) throws IOException,
InterruptedException {
// Folder we are going to watch
// Path folder =
// Paths.get(System.getProperty("C:\\Users\\Isuru\\Downloads"));
File dir = new File("C:\\Users\\Isuru\\Downloads");
watchDirectoryPath(dir.toPath());
}
}
En fait, vous vous êtes mal inscrit aux événements. Seul le dernier écouteur a été enregistré avec le type d'événements ENTRY_DELETE.
Pour vous inscrire à toutes sortes d'événements à la fois, vous devez utiliser:
path.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
Attention! Auto-promotion sans vergogne!
J'ai créé un wrapper autour de Java 1.7's WatchService
qui permet d'enregistrer un répertoire et n'importe quel nombre de glob patterns Cette classe se chargera du filtrage et n'émettra que les événements qui vous intéressent.
DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw
watchService.register( // May throw
new DirectoryWatchService.OnFileChangeListener() {
@Override
public void onFileCreate(String filePath) {
// File created
}
@Override
public void onFileModify(String filePath) {
// File modified
}
@Override
public void onFileDelete(String filePath) {
// File deleted
}
},
<directory>, // Directory to watch
<file-glob-pattern-1>, // E.g. "*.log"
<file-glob-pattern-2>, // E.g. "input-?.txt"
... // As many patterns as you like
);
watchService.start();
Le code complet est dans ce repo .
J'ai fait quelques cours pour ça.
public interface FileAvailableListener {
public void fileAvailable(File file) throws IOException;
}
et
public class FileChange {
private long lastModified;
private long size;
private long lastCheck;
public FileChange(File file) {
this.lastModified=file.lastModified();
this.size=file.length();
this.lastCheck = System.currentTimeMillis();
}
public long getLastModified() {
return lastModified;
}
public long getSize() {
return size;
}
public long getLastCheck() {
return lastCheck;
}
public boolean isStable(FileChange other,long stableTime) {
boolean b1 = (getLastModified()==other.getLastModified());
boolean b2 = (getSize()==other.getSize());
boolean b3 = ((other.getLastCheck()-getLastCheck())>stableTime);
return b1 && b2 && b3;
}
}
et
public class DirectoryWatcher {
private Timer timer;
private List<DirectoryMonitorTask> tasks = new ArrayList<DirectoryMonitorTask>();
public DirectoryWatcher() throws URISyntaxException, IOException, InterruptedException {
super();
timer = new Timer(true);
}
public void addDirectoryMonitoringTask(DirectoryMonitorTask task,long period) {
tasks.add(task);
timer.scheduleAtFixedRate(task, 5000, period);
}
public List<DirectoryMonitorTask> getTasks() {
return Collections.unmodifiableList(tasks);
}
public Timer getTimer() {
return timer;
}
}
et
class DirectoryMonitorTask extends TimerTask {
public final static String DIRECTORY_NAME_ARCHIVE="archive";
public final static String DIRECTORY_NAME_ERROR="error";
public final static String LOCK_FILE_EXTENSION=".lock";
public final static String ERROR_FILE_EXTENSION=".error";
public final static String FILE_DATE_FORMAT="yyyyMMddHHmmssSSS";
private String name;
private FileAvailableListener listener;
private Path directory;
private File directoryArchive;
private File directoryError;
private long stableTime;
private FileFilter filter;
private WatchService watchService;
private SimpleDateFormat dateFormatter = new SimpleDateFormat(FILE_DATE_FORMAT);
private Hashtable<File,FileChange> fileMonitor = new Hashtable<File,FileChange>();
public DirectoryMonitorTask(String name,FileAvailableListener listener,Path directory,long stableTime,FileFilter filter) throws IOException {
super();
this.name=name;
this.listener=listener;
this.directory=directory;
this.stableTime=stableTime;
if (stableTime<1) {
stableTime=1000;
}
this.filter=filter;
validateNotNull("Name",name);
validateNotNull("Listener",listener);
validateNotNull("Directory",directory);
validate(directory);
directoryArchive = new File(directory.toFile(),DIRECTORY_NAME_ARCHIVE);
directoryError = new File(directory.toFile(),DIRECTORY_NAME_ERROR);
directoryArchive.mkdir();
directoryError.mkdir();
//
log("Constructed for "+getDirectory().toFile().getAbsolutePath());
initialize();
//
watchService = FileSystems.getDefault().newWatchService();
directory.register(watchService,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds.ENTRY_MODIFY);
log("Started");
}
private void initialize() {
File[] files = getDirectory().toFile().listFiles();
for (File file : files) {
if (isLockFile(file)) {
file.delete();
} else if (acceptFile(file)) {
fileMonitor.put(file,new FileChange(file));
log("Init file added -"+file.getName());
}
}
}
public SimpleDateFormat getDateFormatter() {
return dateFormatter;
}
public Path getDirectory() {
return directory;
}
public FileAvailableListener getListener() {
return listener;
}
public String getName() {
return name;
}
public WatchService getWatchService() {
return watchService;
}
public long getStableTime() {
return stableTime;
}
public File getDirectoryArchive() {
return directoryArchive;
}
public File getDirectoryError() {
return directoryError;
}
public FileFilter getFilter() {
return filter;
}
public Iterator<File> getMonitoredFiles() {
return fileMonitor.keySet().iterator();
}
@Override
public void run() {
WatchKey key;
try {
key = getWatchService().take();
// Poll all the events queued for the key
for (WatchEvent<?> event : key.pollEvents()) {
@SuppressWarnings("unchecked")
Path filePath = ((WatchEvent<Path>) event).context();
File file = filePath.toFile();
if ((!isLockFile(file)) && (acceptFile(file))) {
switch (event.kind().name()) {
case "ENTRY_CREATE":
//
fileMonitor.put(file,new FileChange(file));
log("File created ["+file.getName()+"]");
break;
//
case "ENTRY_MODIFY":
//
fileMonitor.put(file,new FileChange(file));
log("File modified ["+file.getName()+"]");
break;
//
case "ENTRY_DELETE":
//
log("File deleted ["+file.getName()+"]");
createLockFile(file).delete();
fileMonitor.remove(file);
break;
//
}
}
}
// reset is invoked to put the key back to ready state
key.reset();
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator<File> it = fileMonitor.keySet().iterator();
while (it.hasNext()) {
File file = it.next();
FileChange fileChange = fileMonitor.get(file);
FileChange fileChangeCurrent = new FileChange(file);
if (fileChange.isStable(fileChangeCurrent, getStableTime())) {
log("File is stable ["+file.getName()+"]");
String filename = getDateFormatter().format(new Date())+"_"+file.getName();
File lockFile = createLockFile(file);
if (!lockFile.exists()) {
log("File do not has lock file ["+file.getName()+"]");
try {
Files.createFile(lockFile.toPath());
log("Processing file ["+file.getName()+"]");
getListener().fileAvailable(file);
file.renameTo(new File(getDirectoryArchive(),filename));
log("Moved to archive file ["+file.getName()+"]");
} catch (IOException e) {
file.renameTo(new File(getDirectoryError(),filename));
createErrorFile(file,e);
log("Moved to error file ["+file.getName()+"]");
} finally {
lockFile.delete();
}
} else {
log("File do has lock file ["+file.getName()+"]");
fileMonitor.remove(file);
}
} else {
log("File is unstable ["+file.getName()+"]");
fileMonitor.put(file,fileChangeCurrent);
}
}
}
public boolean acceptFile(File file) {
if (getFilter()!=null) {
return getFilter().accept(file);
} else {
return true;
}
}
public boolean isLockFile(File file) {
int pos = file.getName().lastIndexOf('.');
String extension="";
if (pos!=-1) {
extension = file.getName().substring(pos).trim().toLowerCase();
}
return(extension.equalsIgnoreCase(LOCK_FILE_EXTENSION));
}
private File createLockFile(File file) {
return new File(file.getParentFile(),file.getName()+LOCK_FILE_EXTENSION);
}
private void createErrorFile(File file,IOException exception) {
File errorFile = new File(file.getParentFile(),file.getName()+ERROR_FILE_EXTENSION);
StringWriter sw = null;
PrintWriter pw = null;
FileWriter fileWriter = null;
try {
//
fileWriter = new FileWriter(errorFile);
if (exception!=null) {
sw = new StringWriter();
pw = new PrintWriter(sw);
exception.printStackTrace(pw);
fileWriter.write(sw.toString());
} else {
fileWriter.write("Exception is null.");
}
//
fileWriter.flush();
//
} catch (IOException e) {
} finally {
if (sw!=null) {
try {
sw.close();
} catch (IOException e1) {
}
}
if (pw!=null) {
pw.close();
}
if (fileWriter!=null) {
try {
fileWriter.close();
} catch (IOException e) {
}
}
}
}
private void validateNotNull(String name,Object obj) {
if (obj==null) {
throw new NullPointerException(name+" is null.");
}
}
private void validate(Path directory) throws IOException {
File file = directory.toFile();
if (!file.exists()) {
throw new IOException("Directory ["+file.getAbsolutePath()+"] do not exists.");
} else if (!file.isDirectory()) {
throw new IOException("Directory ["+file.getAbsolutePath()+"] is not a directory.");
} else if (!file.canRead()) {
throw new IOException("Can not read from directory ["+file.getAbsolutePath()+"].");
} else if (!file.canWrite()) {
throw new IOException("Can not write to directory ["+file.getAbsolutePath()+"] .");
}
}
private void log(String msg) {
//TODO
System.out.println("Task ["+getName()+"] "+msg);
}
}
package p1;
import Java.io.File;
import Java.io.IOException;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.Paths;
import static Java.nio.file.LinkOption.NOFOLLOW_LINKS;
import Java.nio.file.StandardWatchEventKinds;
import Java.nio.file.WatchEvent;
import Java.nio.file.WatchKey;
import Java.nio.file.WatchService;
import Java.util.List;
public class WatchForFile {
public void WatchMyFolder(String path )
{
File dir = new File(path);
Path myDir= dir.toPath();
try
{
Boolean isFolder = (Boolean) Files.getAttribute(myDir,"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder)
{
throw new IllegalArgumentException("Path: " + myDir + " is not a folder");
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
System.out.println("Watching path: " + myDir);
try {
WatchService watcher = myDir.getFileSystem().newWatchService();
myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey watckKey = watcher.take();
List<WatchEvent<?>> events = watckKey.pollEvents();
for (WatchEvent event : events) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("Created: " + event.kind().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("Delete: " + event.context().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("Modify: " + event.context().toString());
}
}
}
catch (Exception e)
{
System.out.println("Error: " + e.toString());
}
}
}
Vérifiez ce code ...
https://github.com/omkar9999/FileWatcherHandler
Ce projet permet de regarder des fichiers pour différents événements de fichiers comme créer, modifier et supprimer, puis agir sur ces événements de manière générique.
Comment utiliser?
Créez un objet Path représentant le répertoire à surveiller pour les événements de fichier.
Path path = Paths.get("/home/omkar/test");
Implémentez l'interface FileHandler pour effectuer une action détectée par l'événement de fichier enregistré.
public class FileHandlerTest implements FileHandler {
private static final Logger LOGGER = Logger.getLogger(FileHandlerTest.class.getName());
/*
* This implemented method will delete the file
*
* @see com.io.util.FileHandler#handle(Java.io.File,
* Java.nio.file.WatchEvent.Kind)
*/
public void handle(File file, Kind<?> fileEvent) {
LOGGER.log(Level.INFO,"Handler is triggered for file {0}",file.getPath());
if(fileEvent == StandardWatchEventKinds.ENTRY_CREATE) {
try {
boolean deleted = Files.deleteIfExists(Paths.get(file.getPath()));
assertTrue(deleted);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Créer une instance d'un FileHandler implémenté
FileHandlerTest fileHandlerTest = new FileHandlerTest();
Créez une instance d'un FileWatcher en transmettant le chemin, une instance d'un FileHandler implémenté et les types d'événements de fichier que vous souhaitez surveiller séparés par des virgules.
FileWatcher fileWatcher = new FileWatcher(path, fileHandlerTest, StandardWatchEventKinds.ENTRY_CREATE);
Maintenant, créez et démarrez un nouveau fil.
Thread watcherThread = new Thread(fileWatcher);
watcherThread.start();
Ce thread commencera à interroger vos événements de fichiers enregistrés et invoquera votre méthode de gestion personnalisée une fois l'un des événements enregistrés détecté.
la classe publique FileWatcher implémente Runnable {
private static final Logger LOGGER =Logger.getLogger(FileWatcher.class.getName());
private WatchService watcher;
private FileHandler fileHandler;
private List<Kind<?>> watchedEvents;
private Path directoryWatched;
/**
* @param directory
* @Path directory to watch files into
* @param fileHandler
* @FileHandler implemented instance to handle the file event
* @param watchRecursive
* if directory is to be watched recursively
* @param watchedEvents
* Set of file events watched
*
* @throws IOException
*/
public FileWatcher(Path directory, FileHandler fileHandler, boolean watchRecursive,
WatchEvent.Kind<?>... watchedEvents) throws IOException {
super();
this.watcher = FileSystems.getDefault().newWatchService();
this.fileHandler = fileHandler;
this.directoryWatched = directory;
this.watchedEvents = Arrays.asList(watchedEvents);
if (watchRecursive) {
// register all subfolders
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
LOGGER.log(Level.INFO, "Registering {0} ", dir);
dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
return FileVisitResult.CONTINUE;
}
});
} else {
directory.register(watcher, watchedEvents);
}
}
@SuppressWarnings({ "unchecked" })
public void run() {
LOGGER.log(Level.INFO, "Starting FileWatcher for {0}", directoryWatched.toAbsolutePath());
WatchKey key = null;
while (true) {
try {
key = watcher.take();
if (key != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
WatchEvent<Path> ev = (WatchEvent<Path>) event;
//directory in which file event is detected
Path directory = (Path) key.watchable();
Path fileName = ev.context();
if (watchedEvents.contains(kind)) {
LOGGER.log(Level.INFO, "Invoking handle on {0}", fileName.toAbsolutePath());
fileHandler.handle(directory.resolve(fileName).toFile(), kind);
}
}
key.reset();
}
} catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Polling Thread was interrupted ", ex);
Thread.currentThread().interrupt();
}
}
}
}