X Tutup
//****************************************************************************** //** FileSystemWatcherNative Class //****************************************************************************** /** * JNI code used to monitor changes made to a directory. * ******************************************************************************/ // This file needs to be compiled with _UNICODE flag, since java string uses unicode. #include "stdafx.h" #include "FileSystemWatcherNative.h" #include #include using namespace std; BOOL bWatchSubtree; //flag used to set whether to watch subdirectories DWORD dwNotifyFilter; //notification filter HANDLE hDirectory; //handle to the directory being monitored wstring sDirectory; //a string representing the path to the directory size_t nBufSize = 32*1024; FILE_NOTIFY_INFORMATION* pBuffer = (FILE_NOTIFY_INFORMATION*)calloc(1, nBufSize); FILE_NOTIFY_INFORMATION* pBufferCurrent; //************************************************************************** //** FindFirstChangeNotification //************************************************************************** /** * Class: FileSystemWatcherNative * Method: FindFirstChangeNotification * Signature: (Ljava/lang/String;ZI)J */ JNIEXPORT jlong JNICALL Java_javaxt_io_FileSystemWatcherNative_FindFirstChangeNotification (JNIEnv* env, jclass, jstring filename, jboolean javaWatchSubtree, jint javaNotifyFilter) { //Convert jstring to wstring const jchar *_filename = env->GetStringChars(filename, 0); jsize len = env->GetStringLength(filename); sDirectory.assign(_filename, _filename + len); env->ReleaseStringChars(filename, _filename); //Update Inputs bWatchSubtree = (BOOL)javaWatchSubtree; dwNotifyFilter = //(DWORD)javaNotifyFilter; FILE_NOTIFY_CHANGE_LAST_WRITE| // Triggered when a file or directory has been modified FILE_NOTIFY_CHANGE_DIR_NAME| // Triggered when a directory has been created or deleted FILE_NOTIFY_CHANGE_FILE_NAME; // Triggered when a file has been created or deleted //Call FindFirstChangeNotification HANDLE handle = FindFirstChangeNotificationW(sDirectory.c_str(), bWatchSubtree, dwNotifyFilter); if (handle == INVALID_HANDLE_VALUE || handle == (HANDLE)ERROR_INVALID_FUNCTION){ DWORD errorCode = GetLastError(); stringstream ss; ss << "FindFirstChangeNotification failed. Error Code: " << errorCode; const char* msg = (const char*)( ss.str().c_str()); jclass exceptionClass = env->FindClass("java/lang/Exception"); env->ThrowNew(exceptionClass, msg ); } //Create File Handle hDirectory = CreateFileW( sDirectory.c_str(), // pointer to the directory GENERIC_READ, // access (read/write) mode FILE_SHARE_READ| FILE_SHARE_WRITE| FILE_SHARE_DELETE, // share mode NULL, // security descriptor OPEN_EXISTING, // how to create FILE_FLAG_BACKUP_SEMANTICS, // file attributes NULL // file with attributes to copy ); //Return FindFirstChangeNotification Handle return (jlong)handle; } //************************************************************************** //** FindNextChangeNotification //************************************************************************** /** * Class: FileSystemWatcherNative * Method: FindNextChangeNotification * Signature: (J)V */ JNIEXPORT void JNICALL Java_javaxt_io_FileSystemWatcherNative_FindNextChangeNotification (JNIEnv *javaEnv, jclass, jlong handle) { if (!FindNextChangeNotification((HANDLE) handle)){ DWORD errorCode = GetLastError(); stringstream ss; ss << "FindNextChangeNotification failed. Error Code: " << errorCode; const char* msg = (const char*)( ss.str().c_str()); jclass exceptionClass = javaEnv->FindClass("java/lang/Exception"); javaEnv->ThrowNew(exceptionClass, msg); } } //************************************************************************** //** FindCloseChangeNotification //************************************************************************** /** * Class: FileSystemWatcherNative * Method: FindCloseChangeNotification * Signature: (J)V */ JNIEXPORT void JNICALL Java_javaxt_io_FileSystemWatcherNative_FindCloseChangeNotification (JNIEnv *javaEnv, jclass, jlong handle) { if (!FindCloseChangeNotification((HANDLE) handle)){ DWORD errorCode = GetLastError(); stringstream ss; ss << "FindCloseChangeNotification failed. Error Code: " << errorCode; const char* msg = (const char*)( ss.str().c_str()); jclass exceptionClass = javaEnv->FindClass("java/lang/Exception"); javaEnv->ThrowNew(exceptionClass, msg); } //Close File Handle if (hDirectory!=NULL){ CloseHandle(hDirectory); } } //************************************************************************** //** WaitForSingleObject //************************************************************************** /** * Class: FileSystemWatcherNative * Method: WaitForSingleObject * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_javaxt_io_FileSystemWatcherNative_WaitForSingleObject (JNIEnv *javaEnv , jclass, jlong hWaitHandle, jint waitTimeoutMillis) { return WaitForSingleObject((HANDLE) hWaitHandle, (DWORD) waitTimeoutMillis); } std::wstring s2ws(const std::string& s){ int len; int slength = (int)s.length() + 1; len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); wchar_t* buf = new wchar_t[len]; MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); std::wstring r(buf); delete[] buf; return r; } //************************************************************************** //** ReadDirectoryChangesW //************************************************************************** /** * Class: FileSystemWatcherNative * Method: ReadDirectoryChangesW * Signature: (Ljava/lang/String;ZI)J */ JNIEXPORT jstring JNICALL Java_javaxt_io_FileSystemWatcherNative_ReadDirectoryChangesW (JNIEnv *env, jclass) { wstringstream ss; DWORD BytesReturned; if (ReadDirectoryChangesW( hDirectory, // handle to directory pBuffer, // read results buffer nBufSize, // length of buffer bWatchSubtree, // WatchSubtree dwNotifyFilter, // notification filter &BytesReturned, // bytes returned NULL, // overlapped buffer NULL // completion routine )){ //Iterate through the file changes pBufferCurrent = pBuffer; while(pBufferCurrent){ //Get current timestamp time_t d = time(NULL); string date( ctime(&d) ); date.erase(date.find_last_not_of(" \t\n")+1); //right trim //Get action wstring action = L""; switch(pBufferCurrent->Action){ case FILE_ACTION_ADDED: action = L"Create"; break; case FILE_ACTION_REMOVED: action = L"Delete"; break; case FILE_ACTION_MODIFIED: action = L"Modify"; break; case FILE_ACTION_RENAMED_OLD_NAME: action = L"Rename"; break; case FILE_ACTION_RENAMED_NEW_NAME: action = L"Renam2"; break; } //Get filename WCHAR* _filename = pBufferCurrent->FileName; int len = (int)pBufferCurrent->FileNameLength/2; wstring filename; filename.assign(_filename, _filename + len); //Join date, action, and filename into 1 event string ss << L"[" << s2ws(date) << L"] " << action << L" " << sDirectory << filename << L"\n"; //Update pBufferCurrent if (pBufferCurrent->NextEntryOffset) pBufferCurrent = (FILE_NOTIFY_INFORMATION*)(((BYTE*)pBufferCurrent) + pBufferCurrent->NextEntryOffset); else pBufferCurrent = NULL; } //end while pBufferCurrent } wstring event = ss.str(); int len = event.size(); jchar* raw = new jchar[len]; memcpy(raw, event.c_str(), len*sizeof(wchar_t)); jstring result = env->NewString(raw, len); delete[] raw; return result; }
X Tutup