WatchService (전체 디렉토리가 아님)를 사용하여 단일 파일 변경을 볼 수 있습니까?
디렉토리 대신 파일을 등록하려고 할 때 java.nio.file.NotDirectoryException
던져집니다. 전체 디렉토리가 아닌 단일 파일 변경을 수신 할 수 있습니까?
디렉토리에서 원하는 파일에 대한 이벤트를 필터링하십시오.
final Path path = FileSystems.getDefault().getPath(System.getProperty("user.home"), "Desktop");
System.out.println(path);
try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
final WatchKey wk = watchService.take();
for (WatchEvent<?> event : wk.pollEvents()) {
//we only register "ENTRY_MODIFY" so the context is always a Path.
final Path changed = (Path) event.context();
System.out.println(changed);
if (changed.endsWith("myFile.txt")) {
System.out.println("My file has changed");
}
}
// reset the key
boolean valid = wk.reset();
if (!valid) {
System.out.println("Key has been unregisterede");
}
}
}
여기에서 변경된 파일이 "myFile.txt"인지 확인합니다.
아니요 파일을 등록 할 수 없습니다. 감시 서비스가이 방식으로 작동하지 않습니다. 그러나 디렉토리를 등록 하면 실제로 디렉토리 자체의 변경이 아니라 디렉토리 하위 (파일 및 하위 디렉토리)의 변경 사항을 감시 합니다.
파일을 감시하려면 감시 서비스에 포함 된 디렉토리를 등록합니다. Path.register () 설명서에 따르면 다음과 같습니다.
WatchKey java.nio.file.Path.register (WatchService 감시자, Kind [] 이벤트, 수정 자 ... 수정 자)에서 IOException 발생
이 경로에있는 파일을 감시 서비스에 등록합니다.
이 릴리스에서이 경로는 존재하는 디렉토리를 찾습니다. 디렉터리는 감시 서비스에 등록 되어 디렉터리의 항목을 감시 할 수 있습니다.
그런 다음 항목에 대한 이벤트를 처리하고 이벤트의 컨텍스트 값을 확인하여 관심있는 파일과 관련된 이벤트를 감지해야합니다. 컨텍스트 값은 항목의 이름을 나타냅니다 (실제로는 정확히 하위 이름 인 상위 경로에 대한 항목의 경로). 여기 에 예가 있습니다 .
디렉토리를 감시하고 특정 파일을 필터링해야한다는 다른 대답은 옳습니다. 그러나 아마도 백그라운드에서 실행되는 스레드를 원할 것입니다. 수락 된 답변은 무기한 차단할 수 watchService.take();
있으며 WatchService를 닫지 않습니다. 별도의 스레드에 적합한 솔루션은 다음과 같습니다.
public class FileWatcher extends Thread {
private final File file;
private AtomicBoolean stop = new AtomicBoolean(false);
public FileWatcher(File file) {
this.file = file;
}
public boolean isStopped() { return stop.get(); }
public void stopThread() { stop.set(true); }
public void doOnChange() {
// Do whatever action you want here
}
@Override
public void run() {
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
Path path = file.toPath().getParent();
path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
while (!isStopped()) {
WatchKey key;
try { key = watcher.poll(25, TimeUnit.MILLISECONDS); }
catch (InterruptedException e) { return; }
if (key == null) { Thread.yield(); continue; }
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
@SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
if (kind == StandardWatchEventKinds.OVERFLOW) {
Thread.yield();
continue;
} else if (kind == java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY
&& filename.toString().equals(file.getName())) {
doOnChange();
}
boolean valid = key.reset();
if (!valid) { break; }
}
Thread.yield();
}
} catch (Throwable e) {
// Log or rethrow the error
}
}
}
나는 받아 들여진 대답 과이 기사 에서 일해 보았다 . 이 스레드를 사용하고 스레드를 new FileWatcher(new File("/home/me/myfile")).start()
호출 stopThread()
하여 중지 할 수 있어야합니다 .
Apache는 메서드가 있는 FileWatchDog 클래스를 제공합니다 doOnChange
.
private class SomeWatchFile extends FileWatchdog {
protected SomeWatchFile(String filename) {
super(filename);
}
@Override
protected void doOnChange() {
fileChanged= true;
}
}
원하는 곳에서이 스레드를 시작할 수 있습니다.
SomeWatchFile someWatchFile = new SomeWatchFile (path);
someWatchFile.start();
FileWatchDog 클래스는 파일의 lastModified()
타임 스탬프를 폴링합니다 . Java NIO의 기본 WatchService는 알림이 즉각적이기 때문에 더 효율적입니다.
개별 파일을 직접 볼 수는 없지만 필요하지 않은 파일은 필터링 할 수 있습니다.
내 FileWatcher
클래스 구현 은 다음과 같습니다 .
import java.io.File;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import static java.nio.file.StandardWatchEventKinds.*;
public abstract class FileWatcher
{
private Path folderPath;
private String watchFile;
public FileWatcher(String watchFile)
{
Path filePath = Paths.get(watchFile);
boolean isRegularFile = Files.isRegularFile(filePath);
if (!isRegularFile)
{
// Do not allow this to be a folder since we want to watch files
throw new IllegalArgumentException(watchFile + " is not a regular file");
}
// This is always a folder
folderPath = filePath.getParent();
// Keep this relative to the watched folder
this.watchFile = watchFile.replace(folderPath.toString() + File.separator, "");
}
public void watchFile() throws Exception
{
// We obtain the file system of the Path
FileSystem fileSystem = folderPath.getFileSystem();
// We create the new WatchService using the try-with-resources block
try (WatchService service = fileSystem.newWatchService())
{
// We watch for modification events
folderPath.register(service, ENTRY_MODIFY);
// Start the infinite polling loop
while (true)
{
// Wait for the next event
WatchKey watchKey = service.take();
for (WatchEvent<?> watchEvent : watchKey.pollEvents())
{
// Get the type of the event
Kind<?> kind = watchEvent.kind();
if (kind == ENTRY_MODIFY)
{
Path watchEventPath = (Path) watchEvent.context();
// Call this if the right file is involved
if (watchEventPath.toString().equals(watchFile))
{
onModified();
}
}
}
if (!watchKey.reset())
{
// Exit if no longer valid
break;
}
}
}
}
public abstract void onModified();
}
이를 사용하려면 다음 onModified()
과 같이 메서드 를 확장하고 구현하면됩니다 .
import java.io.File;
public class MyFileWatcher extends FileWatcher
{
public MyFileWatcher(String watchFile)
{
super(watchFile);
}
@Override
public void onModified()
{
System.out.println("Modified!");
}
}
마지막으로 파일보기를 시작합니다.
String watchFile = System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "Test.txt";
FileWatcher fileWatcher = new MyFileWatcher(watchFile);
fileWatcher.watchFile();
WatchService
디렉토리와 여러 glob 패턴을 등록 할 수있는 Java 1.7 주변의 래퍼를 만들었습니다 . 이 클래스는 필터링을 처리하고 관심있는 이벤트 만 내 보냅니다.
try {
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"
<file-glob-pattern-3>, // E.g. "config.ini"
... // As many patterns as you like
);
watchService.start(); // The actual watcher runs on a new thread
} catch (IOException e) {
LOGGER.error("Unable to register file change listener for " + fileName);
}
완전한 코드는이 저장소에 있습니다.
다른 사람들에 대해서는 확실하지 않지만 기본 WatchService API를 사용하여 단일 파일의 변경 사항을 감시하는 데 필요한 코드 양에 신음합니다. 더 간단해야합니다!
다음은 타사 라이브러리를 사용하는 몇 가지 대안입니다.
- Apache Commons 구성 사용
- Using spring-loaded package from the Spring Framework (didn't find an example implementation for this off-hand, but it looks straight-forward to use)
'IT Share you' 카테고리의 다른 글
Android 앱의 자동 증가 버전 코드 (0) | 2020.11.26 |
---|---|
sw600dp와 w600dp의 차이점은 무엇입니까? (0) | 2020.11.26 |
Enum 멤버를 JSON으로 직렬화 (0) | 2020.11.26 |
PHP Extension intl을 어떻게 활성화 할 수 있습니까? (0) | 2020.11.26 |
현재 Windows 버전이 32 비트인지 64 비트인지 감지 (0) | 2020.11.26 |