#ifndef __FILE_GUARD_H__
#define __FILE_GUARD_H__
#include <functional>
#include <algorithm>
#include <thread>
#include <string>
#include <vector>
#include <map>
class FileGuard
{
public:
//文件动作
enum Action
{
//添加动作
ADDED = 0x00000001,
//删除动作
REMOVED,
//修改动作
MODIFIED,
//重命名旧名称动作
RENAMED_OLD_NAME,
//重命名新名称动作
RENAMED_NEW_NAME,
};
/*
* @brief 构造
*/
FileGuard();
/*
* @brief 析构
*/
~FileGuard();
/*
* @brief 存在路径
* @param[in] path 路径
* @retval true 存在
* @retval false 不存在
*/
bool existPath(const std::string& path) const;
/*
* @brief 添加路径
* @param[in] path 路径(*代表监控所有磁盘)(&代表监控除系统盘以外的磁盘)
* @param[in] subpath 是否监控子路径
* @retval true 成功
* @retval false 失败
*/
bool addPath(const std::string& path, bool subpath = true);
/*
* @brief 删除路径
* @param[in] path 路径
* @return void
*/
void removePath(const std::string& path);
/*
* @brief 清空路径
* @return void
*/
void clearPaths();
/*
* @brief 获取路径
* @return (路径,是否监控子路径)
*/
std::map<std::string, bool> getPaths() const;
/*
* @brief 启动
* @return void
*/
void start();
/*
* @brief 停止
* @return void
*/
void stop();
/*
* @brief 重新开始监控
* @retval true 成功
* @retval false 失败
*/
bool restart();
/*
* @brief 是否启动
* @retval true 已启动
* @retval false 未启动
*/
bool isStart() const;
/*
* @brief 获取最终错误
* @return 最终错误
*/
const char* getLastError() const;
/*
* @brief 添加后缀
* @param[in] suffix 后缀名(.*或*代表所有)
* @return void
*/
void addSuffix(const std::string& suffix);
/*
* @brief 添加后缀
* @param[in] suffixes 后缀名
* @return void
*/
void addSuffixes(const std::vector<std::string>& suffixes);
/*
* @brief 删除后缀
* @param[in] suffix 后缀名
* @return void
*/
void removeSuffix(const std::string& suffix);
/*
* @brief 删除后缀
* @param[in] suffixes 后缀名
* @return void
*/
void removeSuffixes(const std::vector<std::string>& suffixes);
/*
* @brief 清空后缀
* @return void
*/
void clearSuffixes();
/*
* @brief 获取后缀
* @return void
*/
std::vector<std::string> getSuffixes() const;
//改变回调
std::function<void(uint32_t action, const char* file)> onChanged = nullptr;
//错误回调
std::function<void(uint32_t error, const char* path)> onError = nullptr;
//启动回调
std::function<void(uint32_t thread, const char* path)> onStarted = nullptr;
//停止回调
std::function<void(uint32_t thread, const char* path)> onStopped = nullptr;
//所有磁盘的路径
static const char* const ALL_DISK_PATHS;
//除系统以外的磁盘路径
static const char* const EXCEPT_SYSTEM_DISK_PATHS;
//所有后缀名
static const char* const ALL_SUFFIXES;
protected:
/*
* @brief 设置最终错误
* @param[in] fmt 格式化字符串
* @param[in] ... 可变参数
* @return void
*/
void setLastError(const char* fmt, ...);
private:
//参数
struct Arg
{
std::string path;
bool subpath;
char* buffer;
static const size_t size = 1048576;
void* file;
void* wevent;
void* revent;
void* lapped;
bool quit;
unsigned long thread;
unsigned long ecode;
char error[256];
Arg();
~Arg();
Arg(const Arg& o);
Arg& operator=(const Arg& o);
//创建
bool create(const std::string& path, bool subpath);
//释放
void release();
//等待
void wait(size_t timeout = (size_t)-1) const;
//退出
void exit() const;
};
//参数
std::vector<Arg> m_args;
//后缀
std::vector<std::string> m_suffixes;
//错误信息
std::string m_error = "未知错误";
//是否启动
bool m_start = false;
};
#define FILE_GUARD_C_API
#if defined(FILE_GUARD_C_API)
//#define FILE_GUARD_BUILD_DLL
#if defined(FILE_GUARD_BUILD_DLL)
#define FILE_GUARD_DLL_EXPORT __declspec(dllexport)
#else
#define FILE_GUARD_DLL_EXPORT
#endif
#include <stdbool.h>
#include <stdint.h>
enum file_guard_action
{
//添加动作
added_action = 0x00000001,
//删除动作
removed_action,
//修改动作
modified_action,
//重命名旧名称动作
renamed_old_name_action,
//重命名新名称动作
renamed_new_name_action
};
struct file_guard_path
{
char path[512];
bool subpath;
};
#if defined(__cplusplus)
extern "C" {
#endif // !__cplusplus
FILE_GUARD_DLL_EXPORT void* file_guard_initialize();
FILE_GUARD_DLL_EXPORT void file_guard_uninitialize(void* guard);
FILE_GUARD_DLL_EXPORT bool file_guard_exist_path(void* guard, const char* path);
FILE_GUARD_DLL_EXPORT bool file_guard_add_path(void* guard, const char* path, bool subpath);
FILE_GUARD_DLL_EXPORT void file_guard_remove_path(void* guard, const char* path);
FILE_GUARD_DLL_EXPORT void file_guard_clear_paths(void* guard);
FILE_GUARD_DLL_EXPORT int file_guard_get_paths(void* guard, struct file_guard_path* path, int size);
FILE_GUARD_DLL_EXPORT void file_guard_set_on_changed_callback(void* guard,
void (*callback)(uint32_t action, const char* file, void* user), void* user);
FILE_GUARD_DLL_EXPORT void file_guard_set_on_started_callback(void* guard,
void (*callback)(uint32_t thread, const char* path, void* user), void* user);
FILE_GUARD_DLL_EXPORT void file_guard_set_on_stopped_callback(void* guard,
void (*callback)(uint32_t thread, const char* path, void* user), void* user);
FILE_GUARD_DLL_EXPORT void file_guard_set_on_error_callback(void* guard,
void (*callback)(uint32_t error, const char* path, void* user), void* user);
FILE_GUARD_DLL_EXPORT void file_guard_start(void* guard);
FILE_GUARD_DLL_EXPORT void file_guard_start_ex(void* guard, void* user,
void (*on_changed)(uint32_t action, const char* file, void* user),
void (*on_stared)(uint32_t thread, const char* path, void* user),
void (*on_stopped)(uint32_t thread, const char* path, void* user),
void (*on_error)(uint32_t error, const char* path, void* user));
FILE_GUARD_DLL_EXPORT void file_guard_stop(void* guard);
FILE_GUARD_DLL_EXPORT bool file_guard_restart(void* guard);
FILE_GUARD_DLL_EXPORT bool file_guard_is_start(void* guard);
FILE_GUARD_DLL_EXPORT void file_guard_get_error(void* guard, char* error, int size);
FILE_GUARD_DLL_EXPORT void file_guard_add_suffix(void* guard, const char* suffix);
FILE_GUARD_DLL_EXPORT void file_guard_remove_suffix(void* guard, const char* suffix);
FILE_GUARD_DLL_EXPORT void file_guard_clear_suffixes(void* gurad);
FILE_GUARD_DLL_EXPORT int file_guard_get_suffixes(void* guard, char (*suffixes)[256], int size);
#if defined(__cplusplus)
}
#endif // !__cplusplus
#endif // !FILE_GUARD_C_API
#endif // !__FILE_GUARD_H__
#include "FileGuard.h"
#include <Windows.h>
#include <io.h>
#if defined(IDEBUG)
#define print(fmt, ...)\
do { \
char buffer[512] = { 0 };\
snprintf(buffer, sizeof(buffer), fmt, ##__VA_ARGS__);\
printf(fmt, ##__VA_ARGS__);\
OutputDebugString(buffer);\
}while(0);
#else
#define print(fmt, ...)
#endif
static std::string unicode2ascii(const std::wstring& str)
{
int size = WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.size(), 0, 0, 0, 0) + 1;
std::unique_ptr<char> buffer(new char[size]);
WideCharToMultiByte(CP_ACP, 0, str.c_str(), (int)str.size(), buffer.get(), size, 0, 0);
buffer.get()[size - 1] = '\0';
return std::string(buffer.get());
}
const char* const FileGuard::ALL_DISK_PATHS = "*";
const char* const FileGuard::EXCEPT_SYSTEM_DISK_PATHS = "&";
const char* const FileGuard::ALL_SUFFIXES = ".*";
FileGuard::FileGuard()
{
}
FileGuard::~FileGuard()
{
stop();
clearPaths();
}
bool FileGuard::existPath(const std::string& path) const
{
bool exist = false;
for (const auto& x : m_args)
{
if (x.path == path)
{
exist = true;
break;
}
}
return exist;
}
bool FileGuard::addPath(const std::string& path, bool subpath)
{
bool result = false, success = true;
do
{
if (_access(path.c_str(), 0) == -1 && path != ALL_DISK_PATHS && path != EXCEPT_SYSTEM_DISK_PATHS)
{
setLastError("%s路径不存在", path.c_str());
break;
}
std::vector<std::string> paths;
if (path == ALL_DISK_PATHS || path == EXCEPT_SYSTEM_DISK_PATHS)
{
auto drives = GetLogicalDrives();
char volume = 'A';
while (drives)
{
if (drives & 1)
{
paths.push_back(std::string(1, volume) + ":\\");
}
volume++;
drives >>= 1;
}
//排除无法监控的盘符
std::vector<std::string> temp;
for (const auto& x : paths)
{
uint32_t type = GetDriveType(x.c_str());
if (type == DRIVE_UNKNOWN ||
type == DRIVE_NO_ROOT_DIR ||
type == DRIVE_REMOTE ||
type == DRIVE_CDROM)
{
continue;
}
temp.push_back(x);
}
paths = temp;
if (path == EXCEPT_SYSTEM_DISK_PATHS)
{
char dir[512] = { 0 };
if (!GetWindowsDirectoryA(dir, sizeof(dir)))
{
setLastError("获取系统目录失败,错误代码:%lu", GetLastError());
break;
}
const std::string win(dir, 3);
for (auto iter = paths.begin(); iter != paths.end(); ++iter)
{
if (*iter == win)
{
paths.erase(iter);
break;
}
}
}
}
else
{
std::string str = path;
char c = str.at(str.length() - 1);
if (c != '\\' && c != '/')
{
str.append("\\");
}
for (auto& x : str)
{
if (x == '/')
{
x = '\\';
}
}
paths.push_back(str);
}
for (const auto& x : paths)
{
if (!existPath(x))
{
Arg arg;
if (!arg.create(x, subpath))
{
success = false;
setLastError(arg.error);
if (path == ALL_DISK_PATHS || path == EXCEPT_SYSTEM_DISK_PATHS)
{
continue;
}
break;
}
m_args.push_back(arg);
}
}
if (!success)
{
for (const auto& x : paths)
{
removePath(x);
}
break;
}
result = true;
} while (false);
return result;
}
void FileGuard::removePath(const std::string& path)
{
for (auto iter = m_args.begin(); iter != m_args.end(); ++iter)
{
if (iter->path == path)
{
iter->release();
m_args.erase(iter);
break;
}
}
}
void FileGuard::clearPaths()
{
for (auto iter = m_args.begin(); iter != m_args.end(); ++iter)
{
iter->release();
}
m_args.clear();
}
std::map<std::string, bool> FileGuard::getPaths() const
{
std::map<std::string, bool> map;
for (const auto& x : m_args)
{
map.insert(std::make_pair(x.path, x.subpath));
}
return map;
}
void FileGuard::start()
{
if (m_suffixes.size() == 1 && m_suffixes[0] == ".*")
{
m_suffixes.clear();
}
for (auto& x : m_args)
{
if (!x.quit)
{
continue;
}
std::thread([&](Arg* arg)->void
{
arg->quit = false;
arg->thread = GetCurrentThreadId();
if (onStarted)
{
onStarted(arg->thread, arg->path.c_str());
}
bool success = true;
DWORD bytes = 0, offset = 0, error = 0;
OVERLAPPED lapped = { 0 };
arg->lapped = static_cast<void*>(&lapped);
lapped.hEvent = arg->revent;
do
{
memset(arg->buffer, 0, arg->size);
print("thread %lu,path %s,start ReadDirectoryChangesW\n", arg->thread, arg->path.c_str());
if (ReadDirectoryChangesW(arg->file,
arg->buffer,
arg->size,
arg->subpath,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
&bytes,
&lapped,
nullptr))
{
print("thread %lu,path %s,start GetOverlappedResult\n", arg->thread, arg->path.c_str());
if (GetOverlappedResult(arg->file, &lapped, &bytes, TRUE))
{
FILE_NOTIFY_INFORMATION* info = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(arg->buffer);
do
{
if (onChanged)
{
std::wstring ws(info->FileName, info->FileNameLength / sizeof(wchar_t));
std::string s(arg->path + unicode2ascii(ws));
if (!m_suffixes.empty())
{
for (size_t i = 0; i < m_suffixes.size(); ++i)
{
size_t npos = s.find_last_of('.');
if (npos != std::string::npos)
{
std::string suffix = s.substr(npos);
std::transform(suffix.begin(), suffix.end(), suffix.begin(), std::tolower);
if (suffix == m_suffixes[i])
{
onChanged(info->Action, s.c_str());
break;
}
}
}
}
else
{
onChanged(info->Action, s.c_str());
}
}
offset = info->NextEntryOffset;
info = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(reinterpret_cast<uint8_t*>(info) + offset);
} while (offset);
}
else
{
arg->ecode = GetLastError();
print("thread %lu,path %s,GetOverlappedResult false,error %lu\n",
arg->thread, arg->path.c_str(), arg->ecode);
if (arg->ecode == ERROR_OPERATION_ABORTED)
{
arg->ecode = 0;
break;
}
success = false;
}
print("thread %lu,path %s,start ResetEvent\n", arg->thread, arg->path.c_str());
if (!ResetEvent(lapped.hEvent))
{
arg->ecode = GetLastError();
print("thread %lu,path %s,ResetEvent false,error %lu\n",
arg->thread, arg->path.c_str(), arg->ecode);
success = false;
break;
}
}
else
{
arg->ecode = GetLastError();
print("thread %lu,path %s,ReadDirectoryChangeW false,error %lu\n",
arg->thread, arg->path.c_str(), arg->ecode);
success = false;
break;
}
print("thread %lu,path %s,start WaitForSingleObject\n", arg->thread, arg->path.c_str());
error = WaitForSingleObject(arg->wevent, 0);
} while (error == WAIT_TIMEOUT);
if (onError && !success)
{
onError(arg->ecode, arg->path.c_str());
}
if (onStopped)
{
onStopped(arg->thread, arg->path.c_str());
}
print("thread %lu,path %s,thread exit\n", arg->thread, arg->path.c_str());
arg->quit = true;
}, &x).detach();
}
m_start = true;
}
void FileGuard::stop()
{
m_start = false;
for (auto& x : m_args)
{
x.exit();
x.wait();
}
}
bool FileGuard::restart()
{
stop();
std::vector<Arg> args = m_args;
clearPaths();
for (const auto& x : args)
{
if (!addPath(x.path, x.subpath))
{
return false;
}
}
start();
return true;
}
bool FileGuard::isStart() const
{
return m_start;
}
const char* FileGuard::getLastError() const
{
return m_error.c_str();
}
void FileGuard::addSuffix(const std::string& suffix)
{
std::string data(suffix);
std::transform(data.begin(), data.end(), data.begin(), std::tolower);
bool find = false, add = false;
for (const auto& x : m_suffixes)
{
if (x == data)
{
find = true;
break;
}
}
if (!find)
{
if (data.find_last_of('.') == std::string::npos)
{
add = true;
}
m_suffixes.push_back(add ? "." + data : data);
}
for (const auto& x : m_suffixes)
{
if (x == ALL_SUFFIXES || std::string(".") + x == ALL_SUFFIXES)
{
m_suffixes.clear();
m_suffixes.push_back(ALL_SUFFIXES);
break;
}
}
}
void FileGuard::addSuffixes(const std::vector<std::string>& suffixes)
{
m_suffixes = suffixes;
}
void FileGuard::removeSuffix(const std::string& suffix)
{
std::string data(suffix);
std::transform(data.begin(), data.end(), data.begin(), std::tolower);
for (auto iter = m_suffixes.begin(); iter != m_suffixes.end(); ++iter)
{
if (*iter == data)
{
m_suffixes.erase(iter);
break;
}
}
}
void FileGuard::removeSuffixes(const std::vector<std::string>& suffixes)
{
for (auto iter = suffixes.begin(); iter != suffixes.end(); ++iter)
{
std::string data(*iter);
std::transform(data.begin(), data.end(), data.begin(), std::tolower);
m_suffixes.erase(std::remove(m_suffixes.begin(), m_suffixes.end(), data), m_suffixes.end());
}
}
void FileGuard::clearSuffixes()
{
m_suffixes.clear();
}
std::vector<std::string> FileGuard::getSuffixes() const
{
return m_suffixes;
}
void FileGuard::setLastError(const char* fmt, ...)
{
char buff[512] = { 0 };
va_list ap;
va_start(ap, fmt);
vsnprintf(buff, sizeof(buff), fmt, ap);
va_end(ap);
m_error = buff;
}
FileGuard::Arg::Arg()
:subpath(false),
buffer(nullptr),
file(INVALID_HANDLE_VALUE),
wevent(nullptr),
revent(nullptr),
lapped(nullptr),
quit(true),
thread(0),
ecode(0),
error{ 0 }
{
}
FileGuard::Arg::~Arg()
{
if (buffer)
{
delete[] buffer;
buffer = nullptr;
}
}
FileGuard::Arg::Arg(const Arg& o)
{
path = o.path;
subpath = o.subpath;
if (o.buffer)
{
buffer = new char[o.size];
memcpy(buffer, o.buffer, o.size);
}
file = o.file;
wevent = o.wevent;
revent = o.revent;
lapped = o.lapped;
quit = o.quit;
thread = o.thread;
ecode = o.ecode;
memcpy(error, o.error, sizeof(error));
}
FileGuard::Arg& FileGuard::Arg::operator=(const Arg& o)
{
if (!memcmp(this, &o, sizeof(Arg)))
{
return *this;
}
path = o.path;
subpath = o.subpath;
if (o.buffer)
{
buffer = new char[o.size];
memcpy(buffer, o.buffer, o.size);
}
file = o.file;
wevent = o.wevent;
revent = o.revent;
lapped = o.lapped;
quit = o.quit;
thread = o.thread;
ecode = o.ecode;
memcpy(error, o.error, sizeof(error));
return *this;
}
bool FileGuard::Arg::create(const std::string& path, bool subpath)
{
bool result = false;
do
{
const char c = path.at(path.length() - 1);
this->path = (c != '\\' && c != '/') ? (path + "\\") : (path);
for (auto& x : this->path)
{
if (x == '/')
x = '\\';
}
this->subpath = subpath;
file = CreateFileA(path.c_str(),
GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
nullptr);
if (file == INVALID_HANDLE_VALUE)
{
sprintf_s(error, "获取%s路径句柄失败,错误代码:%lu", path.c_str(), ::GetLastError());
break;
}
wevent = CreateEventA(nullptr, true, false, nullptr);
if (wevent == nullptr)
{
CloseHandle(file);
file = INVALID_HANDLE_VALUE;
sprintf_s(error, "创建%s路径事件失败,错误代码:%lu", path.c_str(), ::GetLastError());
break;
}
revent = CreateEventA(nullptr, true, false, nullptr);
if (revent == nullptr)
{
CloseHandle(file);
file = INVALID_HANDLE_VALUE;
CloseHandle(wevent);
wevent = nullptr;
sprintf_s(error, "创建%s路径折叠失败,错误代码:%lu", path.c_str(), ::GetLastError());
break;
}
buffer = new char[size];
if (buffer == nullptr)
{
CloseHandle(file);
file = INVALID_HANDLE_VALUE;
CloseHandle(wevent);
wevent = nullptr;
CloseHandle(revent);
revent = nullptr;
sprintf_s(error, "创建%s路径缓冲区失败,内存不足", path.c_str());
break;
}
memset(buffer, 0, size);
result = true;
} while (false);
return result;
}
void FileGuard::Arg::release()
{
if (file != INVALID_HANDLE_VALUE)
{
CloseHandle(file);
file = INVALID_HANDLE_VALUE;
}
if (wevent)
{
CloseHandle(wevent);
wevent = nullptr;
}
if (revent)
{
CloseHandle(revent);
revent = nullptr;
}
if (lapped)
{
lapped = nullptr;
}
if (buffer)
{
delete[] buffer;
buffer = nullptr;
}
}
void FileGuard::Arg::wait(size_t timeout) const
{
auto tick = GetTickCount64();
while (!quit)
{
if (GetTickCount64() - tick > timeout)
{
break;
}
}
}
void FileGuard::Arg::exit() const
{
if (file != INVALID_HANDLE_VALUE)
{
CancelIoEx(file, static_cast<LPOVERLAPPED>(lapped));
}
}
#if defined(FILE_GUARD_C_API)
#define get_guard(x) ((FileGuard*)(x))
void* file_guard_initialize()
{
return new FileGuard;
}
void file_guard_uninitialize(void* guard)
{
if (guard)
{
delete static_cast<FileGuard*>(guard);
}
}
bool file_guard_exist_path(void* guard, const char* path)
{
return get_guard(guard)->existPath(path);
}
bool file_guard_add_path(void* guard, const char* path, bool subpath)
{
return get_guard(guard)->addPath(path, subpath);
}
void file_guard_remove_path(void* guard, const char* path)
{
get_guard(guard)->removePath(path);
}
void file_guard_clear_paths(void* guard)
{
get_guard(guard)->clearPaths();
}
int file_guard_get_paths(void* guard, file_guard_path* path, int size)
{
auto map = get_guard(guard)->getPaths();
int index = 0;
for (const auto& x : map)
{
strcpy_s(path[index].path, x.first.c_str());
path[index].subpath = x.second;
if (index + 1 == size)
{
break;
}
}
return index;
}
void file_guard_set_on_changed_callback(void* guard, void(*callback)(uint32_t action, const char* file, void* user), void* user)
{
get_guard(guard)->onChanged = [user, callback](uint32_t action, const char* file) {
callback(action, file, user);
};
}
void file_guard_set_on_started_callback(void* guard, void(*callback)(uint32_t thread, const char* path, void* user), void* user)
{
get_guard(guard)->onStarted = [user, callback](uint32_t thread, const char* path) {
callback(thread, path, user);
};
}
void file_guard_set_on_stopped_callback(void* guard, void(*callback)(uint32_t thread, const char* path, void* user), void* user)
{
get_guard(guard)->onStopped = [user, callback](uint32_t thread, const char* path) {
callback(thread, path, user);
};
}
void file_guard_set_on_error_callback(void* guard, void(*callback)(uint32_t error, const char* path, void* user), void* user)
{
get_guard(guard)->onError = [user, callback](uint32_t error, const char* path) {
callback(error, path, user);
};
}
void file_guard_start(void* guard)
{
get_guard(guard)->start();
}
void file_guard_start_ex(void* guard, void* user,
void(*on_changed)(uint32_t action, const char* file, void* user),
void(*on_started)(uint32_t thread, const char* path, void* user),
void(*on_stopped)(uint32_t thread, const char* path, void* user),
void(*on_error)(uint32_t error, const char* path, void* user))
{
get_guard(guard)->onChanged = [user, on_changed](uint32_t action, const char* file) {
on_changed(action, file, user);
};
get_guard(guard)->onStarted = [user, on_started](uint32_t thread, const char* path) {
on_started(thread, path, user);
};
get_guard(guard)->onStopped = [user, on_stopped](uint32_t thread, const char* path) {
on_stopped(thread, path, user);
};
get_guard(guard)->onError = [user, on_error](uint32_t error, const char* path) {
on_error(error, path, user);
};
get_guard(guard)->start();
}
void file_guard_stop(void* guard)
{
get_guard(guard)->stop();
}
bool file_guard_restart(void* guard)
{
return get_guard(guard)->restart();
}
bool file_guard_is_start(void* guard)
{
return get_guard(guard)->isStart();
}
void file_guard_get_error(void* guard, char* error, int size)
{
strncpy_s(error, size, get_guard(guard)->getLastError(), _TRUNCATE);
}
void file_guard_add_suffix(void* guard, const char* suffix)
{
get_guard(guard)->addSuffix(suffix);
}
void file_guard_remove_suffix(void* guard, const char* suffix)
{
get_guard(guard)->removeSuffix(suffix);
}
void file_guard_clear_suffixes(void* guard)
{
get_guard(guard)->clearSuffixes();
}
int file_guard_get_suffixes(void* guard, char(*suffixes)[256], int size)
{
auto datas = get_guard(guard)->getSuffixes();
size_t i = 0;
for (; i < datas.size(); ++i)
{
strcpy_s(suffixes[i], datas[i].c_str());
if (i == size - 1)
{
i++;
break;
}
}
return (int)i;
}
#endif // !FILE_GUARD_BUILD_DLL
//测试代码
#include "FileGuard.h"
#include <stdio.h>
//C++风格
#if defined(__cplusplus)
int main()
{
FileGuard guard;
guard.addPath("*");//*代表监控当前计算机中,所有的磁盘
guard.onChanged = [](uint32_t action, const char* file) {
switch (action)
{
case FileGuard::Action::ADDED:
printf("onChanged-> 文件[%s]添加动作\n", file);
break;
case FileGuard::Action::MODIFIED:
printf("onChanged-> 文件[%s]修改动作\n", file);
break;;
case FileGuard::Action::REMOVED:
printf("onChanged-> 文件[%s]移除动作\n", file);
break;
case FileGuard::Action::RENAMED_OLD_NAME:
printf("onChanged-> 文件[%s]改名动作(旧)\n", file);
break;
case FileGuard::Action::RENAMED_NEW_NAME:
printf("onChanged-> 文件[%s]改名动作(新)\n", file);
break;
default:
break;
}
};
guard.onError = [](uint32_t error, const char* path) {
printf("onError-> 错误代码:%lu,路径:%s\n", error, path);
};
guard.onExit = [](uint32_t thread, const char* path) {
printf("onExit-> 线程:%lu,路径:%s\n", thread, path);
};
guard.start();
getchar();
guard.stop();
return 0;
}
#else
//C风格,如果使用C语言进行操作,需要将FileGuard编译为静态库或动态库,
//头文件中,删除C++的声明.因为是用C++写的,外面套了一层C语言的壳进行封装.
#pragma comment(lib, "FileGuard.lib")
void file_guard_on_changed(uint32_t action, const char* file, void* user)
{
switch (action)
{
case FileGuard::Action::ADDED:
printf("on_changed-> 文件[%s]添加动作\n", file);
break;
case FileGuard::Action::MODIFIED:
printf("on_changed-> 文件[%s]修改动作\n", file);
break;;
case FileGuard::Action::REMOVED:
printf("on_changed-> 文件[%s]移除动作\n", file);
break;
case FileGuard::Action::RENAMED_OLD_NAME:
printf("on_changed-> 文件[%s]改名动作(旧)\n", file);
break;
case FileGuard::Action::RENAMED_NEW_NAME:
printf("on_changed-> 文件[%s]改名动作(新)\n", file);
break;
default:
break;
}
}
void file_guard_on_exit(uint32_t thread, const char* path, void* user)
{
printf("on_exit-> 路径%s,线程%lu\n", path, thread);
}
void file_guard_on_error(uint32_t error, const char* path, void* user)
{
printf("on_error-> 路径%s,错误代码%lu\n", path, error);
}
int main()
{
void* guard = file_guard_initialize();
file_guard_add_path(guard, "*", true);//*代表监控当前计算机中,所有的磁盘
file_guard_start(guard, NULL,
file_guard_on_changed,
file_guard_on_exit,
file_guard_on_error);
getchar();
file_guard_stop(guard);
file_guard_uninitialize(guard);
return 0;
}
#endif // !__cplusplus
项目展示:
通用DLL下载链接地址: