最近我的 C 盘由蓝色变为红色(磁盘可用空间只有15GB),心里很郁闷,我最近没有安装新软件,磁盘为什么就会满,经过了一番排查后,发现有一个软件会偷偷截屏并存为图片文件,而且几乎每隔两分钟就截屏一次,非常恶心。
为了解决这个问题:
1、需要监控某个文件夹,如果文件夹里面新增了文件,则删除。
2、服务需要运行在后台。
3、服务需要开机自启动。
恰好我最近在学 Rust,所以我就使用 Rust 来练练手。
监控文件夹
rust
// 监控的文件夹路径
let folder_to_watch = Path::new("D:\\test");
// 创建一个通道用于接收文件系统事件
let (tx, rx) = channel();
// 创建一个文件监控器
let mut watcher = RecommendedWatcher::new(tx, NotifyConfig::default()).expect("无法创建文件监控器");
// 监听指定文件夹的更改事件
watcher.watch(folder_to_watch, RecursiveMode::NonRecursive).expect("无法监听文件夹");
// 进入事件监听循环
loop {
match rx.recv() {
Ok(event) => match event {
Ok(event) => {
if event.kind == EventKind::Create(CreateKind::Any) {
for path in event.paths {
remove_file(&path);
}
}
}
Err(e) => error!("错误: {}", e),
},
Err(e) => error!("监控文件错误: {}", e),
}
}
fn remove_file(path: &PathBuf) {
if path.is_file() {
// 尝试删除文件
sleep(Duration::from_secs(1));
match fs::remove_file(&path) {
Ok(_) => info!("成功删除文件: {:?}", path),
Err(e) => {
error!("删除文件失败: {:?}, 错误: {}", path, e)
}
}
}
}
info!
和 error!
宏来自 log
crate。
实现服务
实现服务依赖了 windows-service
服务的主体结构是这样的:
rust
use log::error;
use std::ffi::OsString;
use windows_service::service_dispatcher;
#[macro_use]
extern crate windows_service;
define_windows_service!(ffi_service_main, my_service_main);
const SERVICE_NAME: &str = "FolderMonitor";
fn my_service_main(arguments: Vec<OsString>) {
if let Err(e) = run_service(arguments) {
error!("运行服务错误:{:?}", e);
}
}
fn run_service(_args: Vec<OsString>) -> Result<(), windows_service::Error> {
// 服务入口
// @TODO 监控文件夹
// @TODO 服务运行时,把服务状态改为运行中
// @TODO 服务停止运行时,退出事件监听循环、停止监控文件夹、把服务状态为已停止
Ok(())
}
fn main() -> Result<(), windows_service::Error> {
service_dispatcher::start(SERVICE_NAME, ffi_service_main)?;
Ok(())
}
完整的run_service
代码如下
rust
fn run_service(_args: Vec<OsString>) -> Result<(), windows_service::Error> {
// 初始化日志系统,将日志写入 LOG_FILE
let log_file = OpenOptions::new()
.create(true)
.append(true)
.open(LOG_FILE)
.expect("无法打开日志文件");
// 自定义日志格式:包含日期和时间
let config = ConfigBuilder::new().set_time_format_rfc3339().build();
CombinedLogger::init(vec![
TermLogger::new(
LevelFilter::Warn,
Config::default(),
TerminalMode::Mixed,
ColorChoice::Auto,
),
WriteLogger::new(LevelFilter::Info, config, log_file),
])
.unwrap();
info!("Windows 服务已启动");
// 用于控制主循环的退出
let running = Arc::new(AtomicBool::new(true));
let running_clone = Arc::clone(&running);
// 监控的文件夹路径
let folder_to_watch = Path::new(MONITOR_PATH);
// 创建一个通道用于接收文件系统事件
let (tx, rx) = channel();
// 创建一个文件监控器
let mut watcher =
RecommendedWatcher::new(tx, NotifyConfig::default()).expect("无法创建文件监控器");
// 监听指定文件夹的更改事件
watcher
.watch(folder_to_watch, RecursiveMode::NonRecursive)
.expect("无法监听文件夹");
// 设定 Windows 服务控制处理器
let status_handle =
service_control_handler::register(SERVICE_NAME, move |control| match control {
ServiceControl::Stop => {
info!("收到服务停止命令");
running_clone.store(false, Ordering::Relaxed); // 更新状态,让主循环退出
return ServiceControlHandlerResult::NoError;
}
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
_ => ServiceControlHandlerResult::NotImplemented,
})
.unwrap();
status_handle
.set_service_status(ServiceStatus {
service_type: ServiceType::OWN_PROCESS,
current_state: ServiceState::Running,
controls_accepted: ServiceControlAccept::STOP,
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
process_id: None,
})
.unwrap();
info!("开始监控文件夹: {}", folder_to_watch.to_string_lossy());
// 进入事件监听循环
while running.load(Ordering::Relaxed) {
match rx.recv_timeout(Duration::from_secs(1)) {
Ok(event) => match event {
Ok(event) => {
if event.kind == EventKind::Create(CreateKind::Any) {
for path in event.paths {
remove_file(&path);
}
}
}
Err(e) => error!("错误: {}", e),
},
Err(_) => {}
}
}
// 停止监听文件夹变动
if let Err(e) = watcher.unwatch(folder_to_watch) {
error!("停止监控文件夹失败: {}", e);
} else {
info!("已停止监控文件夹: {}", folder_to_watch.to_string_lossy());
}
status_handle
.set_service_status(ServiceStatus {
service_type: ServiceType::OWN_PROCESS,
current_state: ServiceState::Stopped,
controls_accepted: ServiceControlAccept::empty(),
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
process_id: None,
})
.unwrap();
info!("服务已停止");
Ok(())
}
安装服务
以管理员身份运行命令行提示符
应用
cmd
sc create FolderMonitor binPath= "D:\Program Files\folder-monitor\folder_monitor_service.exe" # 创建服务
sc start FolderMonitor # 启动服务
sc stop FolderMonitor # 停止服务
参考
注:以上研究成果是在ChatGPT
帮助下完成。