只要我不学习,就不会遇到困难

本文介绍在Qt中通过QProcess灵活注册Windows定时任务,以注册每个星期的星期五、星期天下午六点创建文件夹为例.

一、准备工作

 Windows上注册定时任务一般使用schtasks命令,可以参考官网文档:schtasks.exe,但是使用schtasks提供的语法不是一个很好的选择(组合太复杂,很难定制灵活的定时任务)。
 取巧方式:schtasks.exe /create /tn [taskname] /xml [xmlpath],schtasks提供通过xml文本注册定时任务,只需要提前定义好xml文本,即可轻松注册定时任务。


二、定时任务XML

 打开计算机管理(本地)-任务计划程序-任务计划程序库,可以查看本机的Windows定时任务,通过Windows提供的界面注册一个定时任务,然后将其导出成xml定时任务文件。以下是我导出的一个模板,触发器为每周执行的XML文件,大家可以根据需要自行导出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date></Date>
<Author></Author>
<Description></Description>
<URI></URI>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<StartBoundary></StartBoundary>
<Enabled>true</Enabled>
<ScheduleByWeek>
<DaysOfWeek>
<Sunday/>
<Monday/>
<Tuesday/>
<Wednesday/>
<Thursday/>
<Friday/>
<Saturday/>
</DaysOfWeek>
<WeeksInterval></WeeksInterval>
</ScheduleByWeek>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<LogonType>InteractiveToken</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<Duration>PT10M</Duration>
<WaitTimeout>PT1H</WaitTimeout>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command></Command>
<Arguments></Arguments>
</Exec>
</Actions>
</Task>

部分参数含义:

URI:任务名称
Description:任务描述
WeeksInterval:每隔多少星期执行
Command:bat或exe执行程序的绝对路径
Arguments:程序参数,多个参数逗号分隔
Date: 任务执行时间,格式:yyyy-MM-ddThh:mm:ss
Author:任务创建者,可通过QDir获取:QDir::home().dirName()
DaysOfWeek:定义星期几执行定时任务,比如定义星期一、三执行:<DaysOfWeek><Monday/><Wednesday/></DaysOfWeek>
UserId:计算机ID,这里我将其删掉了,是根据不同机器自行生成的,如果保留此模板就不能在其它机器上使用,算一个坑(已踩)


三、创建文件夹bat文件

 bat文件接收外部传参,bat文件绝对路径对应Command,参数对应Arguments,这里以创建文件夹举例,大家可以根据需要自行定制bat文件.

1
2
3
4
5
@echo off
set dir=%1%
set folder=%2%
set datetime=%Date:~0,4%%Date:~5,2%%Date:~8,2%_%time:~0,2%%time:~3,2%
md "%dir%/%folder%_%datetime%"

备注:bat文件常规最多接收9个外部传参,坑.


四、注册定时任务

 使用Qt的QProcess,定时注册每个星期的星期五、星期日执行创建文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
QString strXmlPath = "F:/schtasks.xml";
QString strTempXml = "F:/schtasks_temp.xml";
QString strCommand = "F:/schtasks.bat";
QString strTaskName = "task";
QString strTargetTime = "2021-01-05T18:00:00";
QStringList arguments{"F:/", "ss"};


QString strXML;
QFile file(strXmlPath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QDomDocument doc;
if (!doc.setContent(&file))
{
file.close();
return;
}
strXML = doc.toString();
file.close();
}

// 每隔一个星期,星期五、星期天执行
strXML.remove("<Monday/>");
strXML.remove("<Tuesday/>");
strXML.remove("<Wednesday/>");
strXML.remove("<Thursday/>");
strXML.remove("<Saturday/>");
strXML.replace("<WeeksInterval/>", "<WeeksInterval>1</WeeksInterval>");
// 定时任务名称、创建日期、创建者、描述、触发时间
strXML.replace("<URI/>", "<URI>" + strTaskName + "</URI>");
strXML.replace("<Date/>", "<Date>" + strTargetTime + "</Date>");
strXML.replace("<Author/>", "<Author>" + QDir::home().dirName() + "</Author>");
strXML.replace("<StartBoundary/>", "<StartBoundary>" + strTargetTime + "</StartBoundary>");
// 程序路径、参数
strXML.replace("<Command/>", "<Command>" + strCommand + "</Command>");
strXML.replace("<Arguments/>", "<Arguments>" + arguments.join(",") + "</Arguments>");

// 将strXML文本以GBK格式写入临时文件,注意GBK

QFile tempfile(strTempXml);
if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
{
QString strUnicode = QTextCodec::codecForName("gbk")->toUnicode(strXML.toLocal8Bit().data());
QByteArray data = QTextCodec::codecForName("gbk")->fromUnicode(strUnicode);
tempfile.write(data);
tempfile.close();
}

QProcess process;
process.setProgram("C://Windows//System32//schtasks.exe");
QStringList argument;
argument << "/create" << "/tn" << strTaskName << "/xml" << strTempXml;
process.setArguments(argument);
process.start();
process.waitForStarted();
process.waitForFinished();
QString strRes = QString::fromLocal8Bit(process.readAllStandardOutput());

 实际工作是针对MySQL、Oracle等数据源做定时任务管理,支持每天、每周、每月创建定时备份任务,业务代码没有这么粗糙. 大家可以根据这个例子,使用不同XML文件拓展定时任务,定制bat执行文件实现业务.


五、schtasks实用命令

 以下均是cmd命令,可以使用QProcess实现程序调用,根据readAllStandardOutput获取返回值判断结果.

1.强制删除定时任务

1
2
// name 任务名称
schtasks /delete /tn name /f

2.修改定时任务状态(可用、禁用)

1
2
3
// name 任务名称
schtasks /change /tn name /enable
schtasks /change /tn name /disable

3.查询定时任务是否已被注册,根据返回参数判断

1
2
// name 任务名称
schtasks /query /tn name

4.查询某一个定时任务所有信息,以list形式返回

1
2
// name 任务名称
schtasks /tn name /fo list /v

gitee工程地址: https://gitee.com/qiangutime/qt-project/tree/master/schtasks