Monitor Directory and File(I)Notify

本文介绍如何在Ubuntu和RedHat上安装inotify,并通过Java库JNotify来监控指定目录下的文件修改事件。通过示例代码CategoryNotify.java和CategoryListener.java展示了如何设置监听器并获取文件修改通知。
Monitor Directory and File(I)Notify

1. Install inotify on Ubuntu
>sudo apt-get install Inotify-tools

2. Install inotify on redhat
http://inotify-tools.sourceforge.net/
>wget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
>tar zxvf inotify-tools-3.14.tar.gz
>cd inotify-tools-3.14
>./configure --prefix=/opt/tools/inotify
>make
>make install

3. we need copy some dll or so to our directory.
find the directory of java.library.path
Put these codes in Java Application and note the directory
System.getProperty("java.library.path")

/usr/lib/jvm/java-6-sun-1.6.0.24/jre/lib/i386/server:
/usr/lib/jvm/java-6-sun-1.6.0.24/jre/lib/i386:
/usr/lib/jvm/java-6-sun-1.6.0.24/jre/../lib/i386:
/usr/lib/jvm/java-6-sun-1.6.0.24/jre/lib/i386/client:
/usr/lib/jvm/java-6-sun-1.6.0.24/jre/lib/i386:
/usr/lib/xulrunner-addons:
/usr/lib/xulrunner-addons:
/usr/lib/xulrunner-addons:
/usr/java/packages/lib/i386:
/lib:
/usr/lib

>sudo cp libjnotify.so /usr/lib/

or we can solve this in another way, at the starting of the java application
java -Djava.library.path=some/folder/path/contain/dll

4. Some test classes
The main test class CategoryNotify.java:
package com.xxxxx.importdata.jnotify;
import net.contentobjects.jnotify.JNotify;
import net.contentobjects.jnotify.JNotifyException;
public class CategoryNotify {
public static void main(String[] args) {
// path to watch
String path = "/home/luohua/life/work/xxxxx/xxxxx-gen/records/";
// System.out.println(System.getProperty("java.library.path"));
// watch mask, specify events you care about,
// or JNotify.FILE_ANY for all events.
// int mask = JNotify.FILE_CREATED | JNotify.FILE_DELETED
// | JNotify.FILE_MODIFIED | JNotify.FILE_RENAMED;
int mask = JNotify.FILE_MODIFIED;
// watch subtree?
boolean watchSubtree = true;
// add actual watch
int watchID = 0;
try {
watchID = JNotify.addWatch(path, mask, watchSubtree,
new CategoryListener());
} catch (JNotifyException e) {
e.printStackTrace();
}
// sleep a little, the application will exit if you
// don't (watching is asynchronous), depending on your
// application, this may not be required
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// to remove watch the watch
boolean res = false;
try {
res = JNotify.removeWatch(watchID);
} catch (JNotifyException e) {
e.printStackTrace();
}
if (!res) {
// invalid watch ID specified.
}
}
}

The listener class CategoryListener.java:
package com.xxxxxx.importdata.jnotify;
import net.contentobjects.jnotify.JNotifyListener;
public class CategoryListener implements JNotifyListener {
public void fileRenamed(int wd, String rootPath, String oldName,
String newName) {
print(wd + "-renamed " + rootPath + " : " + oldName + " -> " + newName);
}
public void fileModified(int wd, String rootPath, String name) {
print(wd + "-modified " + rootPath + " : " + name);
}
public void fileDeleted(int wd, String rootPath, String name) {
print(wd + "-deleted " + rootPath + " : " + name);
}
public void fileCreated(int wd, String rootPath, String name) {
print(wd + "-created " + rootPath + " : " + name);
}
void print(String msg) {
System.err.println(msg);
}
}

And the outputs are as follow:
0-modified records : 2011_06_22/15/15_57_52_5438.txt
0-modified records : 2011_06_22/15/15_57_52_5438.txt/
0-modified records : 2011_06_22/15/15_57_53_2702.txt
0-modified records : 2011_06_22/15/15_57_53_2702.txt/


references:
http://www.iteye.com/topic/1096698
http://hi.baidu.com/lylianyu/blog/item/a26f5dec7e1b16c62e2e2110.html
http://www.blogjava.net/quaff/archive/2006/03/02/33229.html
http://www.java3z.com/cwbwebhome/article/article5/5843.html
http://commons.apache.org/io/apidocs/org/apache/commons/io/monitor/FileAlterationObserver.html

inotify
http://hi.baidu.com/johntech/blog/item/e4a31a3db1ee1ce755e723f4.html
http://www.ibm.com/developerworks/cn/linux/l-inotifynew/
jnotify
http://jnotify.sourceforge.net/
http://whitesock.iteye.com/blog/431147
http://varsoft.iteye.com/blog/873622
#include <iostream> #include <vector> #include <string> #include <thread> #include <mutex> #include <filesystem> #include <sstream> #include <locale> #include <codecvt> #ifdef _WIN32 #include <windows.h> #include <shellapi.h> #define PATH_SEPARATOR L"\\" #define OS_WINDOWS #else #include <unistd.h> #define PATH_SEPARATOR L"/" #endif namespace fs = std::filesystem; // 字符串转换函数 std::wstring ConvertToWString(const std::string& str) { try { // 使用标准库转换工具 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; return converter.from_bytes(str); } catch (...) { // 转换失败时返回默认错误信息 return L"转换错误"; } } // 修复日志输出函数 void OutputLog(const std::wstring& msg) { #ifdef OS_WINDOWS // OutputDebugStringW(msg.c_str()); // 输出到调试器 // OutputDebugStringW(L"\n"); // wprintf(L"%S\n", msg.c_str()); #endif //std::wcout << msg << std::endl; std::wcerr << msg << std::endl; // 输出到控制台 } // 检查管理员权限(跨平台) bool CheckAdminPrivileges() { #ifdef OS_WINDOWS BOOL isAdmin = FALSE; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AdministratorsGroup = nullptr; if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup)) { return false; } if (!CheckTokenMembership(nullptr, AdministratorsGroup, &isAdmin)) { FreeSid(AdministratorsGroup); return false; } FreeSid(AdministratorsGroup); return (isAdmin != FALSE); #else return (getuid() == 0); // Linux root检查 #endif } // 实际的文件夹监控函数(Win32 API实现) void MonitorDirectoryWin32(LPCWSTR path) { HANDLE hDir = CreateFileW( path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr ); if (hDir == INVALID_HANDLE_VALUE) { OutputLog(L"监控失败: " + std::wstring(path)); return; } BYTE buffer[4096]; DWORD bytesReturned; FILE_NOTIFY_INFORMATION* pNotify; while (ReadDirectoryChangesW( hDir, buffer, sizeof(buffer), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, &bytesReturned, nullptr, nullptr)) { pNotify = (FILE_NOTIFY_INFORMATION*)buffer; do { std::wstring filename(pNotify->FileName, pNotify->FileNameLength / sizeof(WCHAR)); switch (pNotify->Action) { case FILE_ACTION_ADDED: OutputLog(L"添加: " + filename); break; case FILE_ACTION_REMOVED: OutputLog(L"删除: " + filename); break; case FILE_ACTION_MODIFIED: OutputLog(L"修改: " + filename); break; case FILE_ACTION_RENAMED_OLD_NAME: OutputLog(L"重命名前: " + filename); break; case FILE_ACTION_RENAMED_NEW_NAME: OutputLog(L"重命名后: " + filename); break; } pNotify = pNotify->NextEntryOffset ? (FILE_NOTIFY_INFORMATION*)((BYTE*)pNotify + pNotify->NextEntryOffset) : nullptr; } while (pNotify); } CloseHandle(hDir); } // 递归监控实现(优化线程管理) void MonitorSubdirectories(const std::wstring& rootDir) { std::vector<std::thread> threads; std::mutex mtx; auto monitorFunc = [&mtx](const std::wstring & path) { OutputLog(L"开始监控: " + path); MonitorDirectoryWin32(path.c_str()); }; // 添加根目录 threads.emplace_back(monitorFunc, rootDir); // 递归添加子目录 try { for (const auto& entry : fs::recursive_directory_iterator(rootDir)) { if (entry.is_directory()) { std::lock_guard lock(mtx); threads.emplace_back(monitorFunc, entry.path().wstring()); } } } catch (const fs::filesystem_error& e) { // 使用转换函数处理异常消息 OutputLog(L"目录遍历错误: " + ConvertToWString(e.what())); } // 等待所有线程完成 for (auto& t : threads) { if (t.joinable()) t.join(); } } int main() { // 设置本地化支持 //setlocale(LC_ALL, "chs"); setlocale(LC_ALL, ".UTF-8"); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); // 管理员权限检查 if (!CheckAdminPrivileges()) { OutputLog(L"⚠️ 需要管理员权限,正在尝试重启..."); #ifdef OS_WINDOWS WCHAR exePath[MAX_PATH]; GetModuleFileNameW(nullptr, exePath, MAX_PATH); SHELLEXECUTEINFOW sei = { sizeof(sei) }; sei.lpVerb = L"runas"; sei.lpFile = exePath; sei.nShow = SW_SHOWNORMAL; if (!ShellExecuteExW(&sei)) { OutputLog(L"重启失败,错误代码: " + std::to_wstring(GetLastError())); } #endif return 1; } const std::wstring targetDir = L"E:\\Toolshed\\RedPanda-CPP\\projects"; OutputLog(L"🔍 开始监控目录: " + targetDir); MonitorSubdirectories(targetDir); return 0; } 帮我完善代码使用GCC写个Win32UI窗口,列表框{序号,路径文件名,文件修改时间,变化状态},右键菜单{开启监听/停止监听,打开文件,定位文件},监听的变化输出到窗口的列表,
08-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值