JAVA监控目录

1.      编写DLL

编写DLL文件是重点,这个DLL得作用就是用C++去监控某个目录,而具体得接口则暴露给JAVA,JAVA负责调用就OK。

原理如下:

根据JAVA传来得需要监视得目录路径,得到这个目录得句柄,同时新建一个线程去监控这个目录发生得一切,而具体得监视是由库函数ReadDirectoryChangesW完成得,它能得到目录修改的信息,然后将其打印出来!

但是在开发过程中,我遇到了很多很多的问题,主要有两个

1.      VC++不识别ReadDirectoryChanges,上网搜索很多的方法都没有成功,直到一位高人指导,解决这个问题,需要两个方面

1. 头部信息

#include "stdafx.h"
#define _WIN32_WINNT 0x0500//必须再windows.h前才有效
#include <windows.h>

2. 设置一些必要的参数

在Project-Setting->C/C++->Preprocessor definitions->加上_WIN32_WINNT=0x0500,WINVER=0x0500那么就OK了

2.      JAVA传递给C++会产生乱码,可能是我的String匹配有错,C++得string难道不是用JAVA得String匹配吗?这个问题我还是没有搞清楚,期待解决,最终我为了试验成功,就再DLL得代码中,默认指定了我得测试路径d:/watch 

下面是具体得C++监控类源码

#include "stdafx.h" 
#define _WIN32_WINNT 0x0500
#include <Winbase.h>
 
#include <string>
#include <cassert>
#include <conio.h>
#include <iostream>
using namespace std;

enum ACTION { ADDED=1, REMOVED=2, MODIFIED=3, RENAMED=4 };//判断文件操作类型得枚举

/*
*处理操作信息得函数
*/
void __stdcall MyDeal( ACTION act, std::string filename1, std::string filename2 )
{
    switch( act )
    {
    case ADDED:
        cout << "Added    - " << filename1 << endl;
        break;
    case REMOVED:
        cout << "Removed  - " << filename1 << endl;
        break;
    case MODIFIED:
        cout << "Modified - " << filename1 << endl;
        break;
    case RENAMED:
        cout << "Rename   - " << filename1 << " " << filename2 << endl;
        break;
    }
};
class FileSystemWatcher
{
public:
    typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, std::string filename1, std::string filename2 );
 
    bool Run( std::string path)
    {
        WatchedDir = path;
       
        DealFun = MyDeal;
       
        DWORD ThreadId;
              cout<<"创建线程"<<endl;
        hThread=CreateThread( NULL,0,Routine,this,0,&ThreadId );
              cout<<"创建结束"<<endl;
              if (NULL!=hThread) {
                     cout<<"创建线程成功"<<endl;
              } else {
                     cout<<"创建线程失败"<<endl;
              }
        return NULL!=hThread;
}
 
//释放资源
    void Close()
    {
        if( NULL != hThread )
        {
            TerminateThread( hThread, 0 );
            hThread = NULL;
        }
        if( INVALID_HANDLE_VALUE != hDir )
        {
            CloseHandle( hDir );
            hDir = INVALID_HANDLE_VALUE;
        }
    }
    FileSystemWatcher() : DealFun(NULL), hThread(NULL), hDir(INVALID_HANDLE_VALUE)
    {
    }
    ~FileSystemWatcher()
    {
        Close();
    }
 
private:
    std::string WatchedDir;
    LPDEALFUNCTION DealFun;
    HANDLE hThread;
    HANDLE hDir;
private:
    FileSystemWatcher( const FileSystemWatcher& );
    FileSystemWatcher operator=( const FileSystemWatcher );
private:
    static DWORD WINAPI Routine( LPVOID lParam )
    {
              cout<<"开始执行线程"<<endl;
        FileSystemWatcher* obj = (FileSystemWatcher*)lParam;
              cout<<"要观察得目录"<<obj->WatchedDir<<endl;
              cout<<direc<<endl;
        obj->hDir = CreateFile(
            obj->WatchedDir.c_str(),
            GENERIC_READ|GENERIC_WRITE,
            FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            NULL
        );
                     cout<<"创建文件"<<endl;
                     if( INVALID_HANDLE_VALUE == obj->hDir ) {
                            cout<<"无效值"<<endl;
                            return false;
                     }
        char buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH) ];
        FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
        DWORD BytesReturned;
cout<<"读取信息"<<endl;
        while(true)
        {
                     
            if( ReadDirectoryChangesW( obj->hDir,
                pNotify,
                sizeof(buf),
                true,
                FILE_NOTIFY_CHANGE_FILE_NAME|
                FILE_NOTIFY_CHANGE_DIR_NAME|
                FILE_NOTIFY_CHANGE_ATTRIBUTES|
                FILE_NOTIFY_CHANGE_SIZE|
                FILE_NOTIFY_CHANGE_LAST_WRITE|
                FILE_NOTIFY_CHANGE_LAST_ACCESS|
                FILE_NOTIFY_CHANGE_CREATION|
                FILE_NOTIFY_CHANGE_SECURITY,
                &BytesReturned,
                NULL,
                NULL ) )
            {
                            cout<<"读取信息成功"<<endl;
                char tmp[MAX_PATH], str1[MAX_PATH], str2[MAX_PATH];
                memset( tmp, 0, sizeof(tmp) );
                WideCharToMultiByte( CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL );
                strcpy( str1, tmp );
 
                if( 0 != pNotify->NextEntryOffset )
                {
                    PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
                    memset( tmp, 0, sizeof(tmp) );
                    WideCharToMultiByte( CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL );
                    strcpy( str2, tmp );
                }
 
                obj->DealFun( (ACTION)pNotify->Action, str1, str2 );
            }
            else
            {
                  cout<<"读取信息失败"<<endl;
                break;
            }
        }
 
        return 0;
    }
};

 有了这个源码(这个源码需要放到.h文件中,负责无法加载使用)以后,就是暴露接口让JAVA调用了,下面是类代码

// FuckYouToDie.cpp : Defines the entry point for the DLL application.
//
//在setting->C/C++   
 // 中加上_WIN32_WINNT=0x0500,WINVER=0x0500
//
#include "stdafx.h"
#include "Fuck.h"//是上面得代码得头文件
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                                    )
{
    return TRUE;
}//默认得入口函数,不用管
 
extern "C" bool __declspec(dllexport) Run() {
       FileSystemWatcher b;
       cout<<"建立B对象"<<endl;
       bool r =  b.Run("d:/watch");
       char c;
       cin>>c;
       while(c != 'q'){
              cin>>c;
       }
       return r;
}

然后进行编译链接,就获得了对于得.dll文件,然后接下来就是用JAVA调用了

2.      JAVAJNA框架去调用

用这个框架调用C++真的是很简单,只需要两个类,一个类

是接口

import com.sun.jna.Library;
 
public interface DLLD extends Library {
 
       boolean Run();
}

继承Library,然后里面得方法要和C++暴露给你得接口一一对应

另外一个就是调用类了

import com.sun.jna.Native;
 
public class DLLDTest {
 
       public static void main(String[] args) {
 
              DLLD loadLibrary = (DLLD) Native.loadLibrary(
                            "E:/网络试验/Tt/src/FuckYouToDie.dll", DLLD.class);
              System.out.println(loadLibrary.Run());
              
       }
}

 注意看代码,JAVA数据类型,要和C++得一一对应才行,然后会找到函数,比如JAVA得int对c++得int,java得char对c++得w_char等,要注意匹配,方法名需要一致