JNotify 是基於操作系統底層機制(Linux inotify / Windows DLL)實現的文件/文件夾動態監控庫,支持遞歸子目錄監聽。本文以郵件系統為例,展示基於 JNotify 的 .eml 文件實時檢測、解析、入庫全流程。
jnotify.jarbin 目錄放入 jnotify.dll / jnotify_64bit.dll(Windows 需求)MailWatcherpublic class MailWatcher {
private static final Logger LOG = LoggerFactory.getLogger(MailWatcher.class);
private String path; // 郵件存儲路徑
public MailWatcher() {
path = Configure.getString("path");
}
public void start() {
new Thread(() -> {
try {
int mask = JNotify.FILE_CREATED | JNotify.FILE_DELETED
| JNotify.FILE_MODIFIED | JNotify.FILE_RENAMED;
int watchId = JNotify.addWatch(path, mask, true, new MailListener());
LOG.info("Watcher 啟動監聽: {} [ID:{}]", path, watchId);
} catch (Exception e) {
LOG.error("監聽啟動失敗", e);
}
}).start();
// 守護主線程
while (true) {
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
}
}
}
MailListener實現 JNotifyListener 接口,核心邏輯在 fileCreated:
.eml 後綴文件EmlFileHelper 解析為 MimeMessagesaveMsg()public void fileCreated(int wd, String rootPath, String name) {
if (!name.endsWith(".eml")) return;
new Thread(() -> {
File file = new File(rootPath, name);
MimeMessage msg = null;
// 初始等待文件寫入完成
sleep(Configure.getLong("wait_first_time"));
// 重試讀取
for (int i = 0; i < Configure.getInt("wait_times"); i++) {
try {
msg = EmlFileHelper.getMimeFile(file);
break;
} catch (Exception e) {
LOG.debug("第 {} 次讀取失敗: {}", i + 1, name);
sleep(Configure.getLong("wait_time_interval") * 1000);
}
}
if (msg == null) { LOG.error("重試後仍讀取失敗: {}", name); return; }
// 過濾發出郵件
if (!Configure.getBoolean("not_intercept_send_email")) {
String receiver = name.substring(0, name.indexOf(File.separator));
String from = MailHelper.getFrom(msg);
if (from.startsWith(receiver + "@")) {
LOG.info("跳過發出郵件: {}", name);
return;
}
}
saveMsg(msg, name);
LOG.info("郵件保存成功: {}", name);
}).start();
}
public class Main {
public static void main(String[] args) throws Exception {
new MailWatcher().start();
}
}