• windows下检測文件改变


            这个主要是应用在我前一篇博客里提到的脚本热载入功能。

    主要实现的功能检測目录内文件的变化(改变、新增、删除、重命名),当发现改变的时候通知lua又一次载入脚本。基本上就是一个windows api的使用。实际应用中会有一些细节须要注意,比方我习惯使用sublime text编辑。而sublime text保存文件不是直接改变文件内容,而是新增一个文件。这些细节情况须要实际使用中微调。

            代码例如以下:

    #include "FileWatcher.h"
    #include "cocos2d.h"
    #include "CCLuaEngine.h"
    
    using namespace cocos2d;
    
    #ifdef WIN32
    //  函数: WatchChanges(LPVOID lpParameter)  
    //  
    //  目的: 监控文件夹的程序  
    //  
    //  凝视:主函数创建线程时制定了这个函数的入口  
    //       届时该子程序将自己主动启动运行。  
    //  备注:由于代码不全,看以下的代码时,主要參考红色的字体部分  
    static int lastChangeTime = 0;
    
    void reloadGame()
    {
    	int time = GetTickCount();
    	if (time - lastChangeTime <= 1000) {
    		// 忽略短时间内的又一次载入请求
    		return;
    	}
    
    	Director::getInstance()->getScheduler()->performFunctionInCocosThread([](){
    		auto engine = LuaEngine::getInstance();
    		ScriptEngineManager::getInstance()->setScriptEngine(engine);
    		lua_State* L = engine->getLuaStack()->getLuaState();
    		lua_getglobal(L, "reloadGame");
    		lua_call(L, 0, 0);
    	});
    }
    DWORD WINAPI WatchChanges(LPVOID lpParameter)//返回版本号信息  
    {
    	wchar_t watchDirectory[512] = {0};
    	MultiByteToWideChar(CP_ACP, 0, (char*)lpParameter, strlen((char*)lpParameter), watchDirectory, sizeof(watchDirectory) / sizeof(wchar_t));
    
    	//创建一个文件夹句柄  
    	HANDLE handle_directory=CreateFile(watchDirectory,  
    		FILE_LIST_DIRECTORY,  
    		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,  
    		NULL,  
    		OPEN_EXISTING,  
    		FILE_FLAG_BACKUP_SEMANTICS,  
    		NULL);
    
    	if(handle_directory==INVALID_HANDLE_VALUE) {  
    		DWORD ERROR_DIR=GetLastError();
    		CCLOG("Open Directory Error");
    	}  
    
    	BOOL watch_state;  
    	while (TRUE)  
    	{
    		char buffer[1024] = {0};
    		DWORD bytesReturned = 0;
    		FILE_NOTIFY_INFORMATION* notify = (FILE_NOTIFY_INFORMATION*)buffer;
    		watch_state=ReadDirectoryChangesW(handle_directory,  (LPVOID)buffer,  
    			sizeof(buffer), TRUE,  
    			FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_LAST_WRITE,  
    			(LPDWORD)&bytesReturned, NULL, NULL);
    
    		int err = GetLastError();
    		if (err == ERROR_INVALID_FUNCTION || err == ERROR_NOTIFY_ENUM_DIR) {
    			return -1;
    		} 
    
    		if(watch_state != 0) {
    			DWORD length=WideCharToMultiByte(0,0,notify->FileName,-1,NULL,0,NULL,NULL);  
    			char fileName[256] = {0};
    			WideCharToMultiByte(0,0,notify->FileName,-1,fileName,length,NULL,NULL);  
    
    			//这里主要就是检測返回的信息,须要注意FILE_NOTIFY_INFORMATION结构体的定义,以便正确调用返回信息
    			if (notify->Action==FILE_ACTION_ADDED) {
    				CCLOG("file add: %s", fileName);
    				// sublime 改动文件是新增一个暂时文件,这个是兼容措施
    				reloadGame();
    			}  
    			if (notify->Action==FILE_ACTION_REMOVED) {
    				CCLOG("file delete: %s", fileName);
    			}  
    			if (notify->Action==FILE_ACTION_MODIFIED) {  
    				CCLOG("file changed: %s", fileName);
    				reloadGame();
    			}  
    
    			//对于以下两种情况。Action本身也是文件名称(可能是old_name也可能是new_name)  
    			if (notify->Action==FILE_ACTION_RENAMED_OLD_NAME) {
    				CCLOG("file rename old name: %s", fileName); 
    			}  
    			if (notify->Action==FILE_ACTION_RENAMED_NEW_NAME) {
    				CCLOG("file rename new name: %s", fileName);
    
    			}
    		}  
    		Sleep(500);  
    	}  
    	return 0;  
    }
    #endif
    
    void startWatch(const char* path)
    {
    #ifdef WIN32
    	static std::string s_path = path;
    	//创建一个线程专门用于监控文件变化  
    	HANDLE TrheadWatch=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WatchChanges,(void*)s_path.c_str(),0,NULL);  
    	CloseHandle(TrheadWatch);
    #endif
    }

    注冊给lua的实现:

    #include "lua_cutil.h"
    //#include <conio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <stdio.h>
    #include <string>
    
    #include "FileWatcher.h"
    
    #include <lua.h>
    #include <lauxlib.h>
    
    int lua_cutil_watch(lua_State *pL)
    {
    	std::string path = luaL_checkstring(pL, 1);
    	startWatch(path.c_str());
    	return 0;
    }
    
    int luaopen_cutil(lua_State *pL)
    {
    	// 注冊lua函数
    	luaL_Reg reg [] = {
    		{"watch",     lua_cutil_watch},
    		{NULL, NULL}
    	};
    
    	luaL_register(pL, "cutil", reg);
    	return 1;
    }
    

    lua中调用的方式:

                    local mainPath = cc.FileUtils:getInstance():fullPathForFilename('Main.lua');
                    mainPath = string.sub(mainPath, 1, string.find(mainPath, 'Main%.lua') - 1);
                    print(mainPath);
                    cutil.watch(mainPath);


  • 相关阅读:
    pycharm突然变成了一个tab变成两个空格,查询无果
    79--JT项目17(Dubbo框架入门)
    79--JT项目17(SOA/RPC思想/zookeeper集群搭建)
    Java instanceof Operator
    12.21.4命名为Windows
    12.20.1汇总功能说明
    第24章分区
    Laravel 中间件的使用
    Laravel session的使用
    Laravel 数据分页
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6897439.html
Copyright © 2020-2023  润新知