目录
二. 文件和目录 (File and Directory Handling)
QCoreApplication、QEventLoop、QEvent、QMetaObject
四. 多线程和并发 (Multithreading and Concurrency)
五. 国际化和本地化 (Internationalization and Localization)
六. 进程和进程间通信 (Process and Inter-Process Communication - IPC)
九. 动态库加载 (Dynamic Library Loading)
一. 核心数据类型 (Core Datatypes)
请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(一)
二. 文件和目录 (File and Directory Handling)
请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(二)
三. 事件系统 (Event System)
QObject
请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(三)
QCoreApplication、QEventLoop、QEvent、QMetaObject
请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(四)
四. 多线程和并发 (Multithreading and Concurrency)
请跳转章节,此处不再重复:QT核心模块QtCore功能详细说明,并给出测试代码(五)
五. 国际化和本地化 (Internationalization and Localization)
-
QLocale
QLocale
类用于管理语言、区域设置等本地化信息,能够根据不同的区域设置显示日期、时间、数字等格式。 -
QTranslator
QTranslator
用于加载翻译文件,以便将应用程序界面翻译成不同的语言。
六. 进程和进程间通信 (Process and Inter-Process Communication - IPC)
QProcess
QProcess 用于启动和管理外部进程,扩展 Qt 程序功能并实现与操作系统的交互,也是 是 Qt Core 模块中连接应用程序与外部系统的重要组件,与信号槽机制深度整合。
-
常见使用场景
调用命令行工具、集成外部应用程序、执行耗时任务、 自动化任务、获取系统信息。 -
核心概念说明
-
外部进程 (External Process)
外部进程是指由 QProcess 在操作系统中启动的独立程序或命令,例如一个可执行文件(.exe)、脚本(.sh、.py)或系统命令(ls、dir)。
-
标准输入 (Standard Input, stdin)
标准输入(stdin)是外部进程接收数据的通道,通常来自键盘或程序提供的输入。在 QProcess 中,可以通过 write() 或 writeData() 方法向外部进程的 stdin 发送数据。
-
标准输出 (Standard Output, stdout)
标准输出(stdout)是外部进程生成的主要输出通道,包含程序的执行结果或日志信息。通过 readAllStandardOutput() 或信号 readyReadStandardOutput() 读取 stdout 数据。
-
标准错误 (Standard Error, stderr)
标准错误(stderr)是外部进程用于输出错误信息或诊断信息的独立通道,与 stdout 分开。通过 readAllStandardError() 或信号 readyReadStandardError() 获取 stderr 数据。
-
退出代码 (Exit Code)
退出代码是外部进程结束时返回的整数值,用于指示其执行结果。0 表示成功,非 0 表示某种错误或异常。通过 exitCode() 方法获取退出代码,帮助判断进程是否正常完成。
-
退出状态 (Exit Status)
退出状态(Exit Status)描述进程终止的方式,通常有两种:正常退出(Normal Exit)和异常终止(Crashed,例如崩溃或被强制终止)。
-
进程 ID (Process ID, PID)
进程 ID(PID)是操作系统分配给每个运行进程的唯一标识符,用于区分不同的进程。
-
进程状态 (Process State)
进程状态表示外部进程的当前运行阶段,包括未启动(NotRunning)、启动中(Starting)和运行中(Running)。
-
工作目录 (Working Directory)
工作目录是外部进程执行时所在的默认文件系统路径,影响相对路径的解析。可以通过 setWorkingDirectory() 设置工作目录。
-
环境变量 (Environment Variables)
环境变量是一组键值对,定义了外部进程运行时的环境设置,例如 PATH、HOME 或自定义变量。在 QProcess 中,可以通过 setProcessEnvironment() 或 setEnvironment() 配置环境变量,以影响进程的行为。
-
进程通道模式 (Process Channel Mode)
进程通道模式定义了 QProcess 如何处理外部进程的输入输出通道(stdin、stdout、stderr)。
-
-
主要方法和函数
-
启动进程
-
start(const QString &program, const QStringList &args, OpenMode mode ):
-
用于以异步方式启动外部进程。
-
program:要运行的可执行程序路径或命令(如 "notepad.exe" 或 "ls")。
-
arguments:传递给程序的参数列表(QStringList 类型)。
-
mode:输入输出通道的打开模式,默认是 ReadWrite,表示可以读写 stdin、stdout 和 stderr。
-
- execute(const QString &program, const QStringList &arguments = QStringList()):
-
用于以同步方式运行外部进程。它会阻塞调用线程,直到进程执行完成并返回退出代码。
-
program:要运行的程序路径或命令。
-
arguments:传递的参数列表(可选)。
-
返回值:进程的退出代码(成功通常为 0,失败为非 0)。
-
- startDetached(const QString &program, const QStringList &args, const QString &workingDirectory = QString(), qint64 *pid = nullptr);
-
用于以分离(detached)模式启动外部进程。启动后,进程独立于 QProcess 和调用程序运行,即使父程序退出,子进程也不会受影响。
-
program:要运行的程序路径或命令。
-
arguments:传递的参数列表。
-
workingDirectory:进程的工作目录(可选)。
-
pid:返回进程的 PID(可选)。
-
返回值:成功启动返回 true,否则返回 false。
-
-
总结对比启用方法
方法
执行方式
交互性
控制权
典型场景
start()
异步
支持读写
可控
实时交互的命令行工具
execute()
同步
无交互
无需后续管理
一次性命令执行
startDetached()
异步
无交互
无控制
独立运行的外部应用程序
-
-
与进程交互
QProcess 提供了多种方法来与外部进程进行交互,包括向进程写入数据(输入)和从进程读取数据(输出或错误)。-
write(const QByteArray &data):
-
用于向外部进程的标准输入(stdin)写入数据。通过它,开发者可以向进程发送命令或数据,模拟用户输入。
-
data:要写入的字节数组(QByteArray 类型)。
-
返回值:成功写入的字节数,失败返回 -1。
-
异步写入:数据写入后立即返回,不等待进程处理。
-
配合信号:通常与 readyRead() 信号结合使用,以读取响应。
-
-
closeWriteChannel():
-
用于关闭 QProcess 的标准输入通道(stdin)。关闭后,无法再通过 write() 向进程写入数据,通常用于通知进程输入已结束。
-
单向关闭:仅关闭 stdin,不影响 stdout 或 stderr 的读取。
-
不可逆:关闭后无法重新打开 stdin。
-
-
readAllStandardOutput()
-
读取外部进程标准输出(stdout)中所有当前可用的数据,返回一个字节数组。
-
一次性读取:读取当前缓冲区中的所有 stdout 数据。
-
非阻塞:如果没有数据,返回空字节数组。
-
配合信号:常与 readyReadStandardOutput() 信号一起使用,避免遗漏数据。
-
-
readAllStandardError()
-
读取外部进程标准错误(stderr)中所有当前可用的数据,返回一个字节数组。
-
独立通道:专门读取 stderr,与 stdout 分开。
-
错误诊断:用于捕获进程执行中的错误或警告。
-
配合信号:可与 readyReadStandardError() 信号结合,实时处理错误。
-
-
readChannel()
-
从当前设置的读取通道(stdout 或 stderr)读取数据。
-
手动控制:需要提前通过 setReadChannel() 指定通道。
-
-
setReadChannel(QProcess::ProcessChannel channel)
-
用于设置当前读取通道,决定后续 readChannel() 调用从 stdout 还是 stderr 读取数据。
-
channel:枚举值,QProcess::StandardOutput(stdout)或 QProcess::StandardError(stderr)。
-
-
交互的核心能力说明:
-
输入:write() 和 closeWriteChannel() 控制 stdin。
-
输出:readAllStandardOutput() 和 readAllStandardError() 分别读取 stdout 和 stderr。
-
灵活读取:readChannel() 和 setReadChannel() 提供动态通道管理。
-
-
-
获取进程信息
QProcess 提供了多种方法来获取外部进程的运行状态和相关信息,包括进程状态、ID、退出码、错误信息以及运行环境等。这些方法帮助开发者监控和管理进程的生命周期。-
state():
-
返回外部进程的当前状态,反映其生命周期阶段。
-
QProcess::NotRunning:进程未启动或已结束。
-
QProcess::Starting:进程正在启动但尚未完全运行。
-
QProcess::Running:进程正在运行。
-
-
pid():返回外部进程的进程 ID(PID),即操作系统分配给该进程的唯一标识符。
-
exitCode() :返回外部进程的退出代码,通常 0 表示成功,非 0 表示失败。
-
exitStatus() :返回进程的退出状态,指示进程是正常结束还是异常终止。
-
QProcess::NormalExit:进程正常退出。
-
QProcess::CrashExit:进程异常终止(如崩溃)。
-
-
error() :返回启动或运行进程时发生的错误类型, QProcess::ProcessError 枚举值。
-
QProcess::FailedToStart:进程启动失败(如文件不存在)。
-
QProcess::Crashed:进程运行时崩溃。
-
QProcess::Timedout:操作超时。
-
QProcess::ReadError/WriteError:读写错误。
-
QProcess::UnknownError:未知错误。
-
-
workingDirectory() 返回进程当前的工作目录,即进程执行时的默认文件路径。
-
environment() 返回进程运行时的环境变量列表,(如 "PATH=/usr/bin")。
-
全面的进程信息获取能力:
-
状态与标识:state() 和 pid() 监控运行状态和 ID。
-
退出信息:exitCode() 和 exitStatus() 分析结束情况。
-
错误处理:error() 诊断问题。
-
环境信息:workingDirectory() 和 environment() 获取运行上下文。
-
-
-
控制进程
QProcess 提供了多种方法来控制外部进程的生命周期和行为,包括终止进程、等待特定事件(如启动、数据可读或结束)。-
kill() 强制终止外部进程,立即无条件结束进程,不给进程清理资源的机会。
-
terminate()
-
请求外部进程优雅地终止,通常通过发送终止信号(如 SIGTERM),允许进程在结束前执行清理操作。
-
优雅退出:给进程机会保存数据或释放资源。
-
不确定性:进程可能忽略终止请求,导致未结束。
-
-
waitForStarted(int msecs = 30000)
-
阻塞当前线程,直到外部进程成功启动或超时。
-
msecs:超时时间(毫秒),默认 30 秒。
-
返回值:true 表示启动成功,false 表示失败或超时。
-
-
waitForReadyReadStandardOutput(int msecs = 30000)
-
阻塞当前线程,直到进程的标准输出(stdout)有数据可读或超时。
-
msecs:超时时间(毫秒),默认 30 秒。
-
返回值:true 表示有数据可读,false 表示超时或错误。
-
-
waitForReadyReadStandardError(int msecs = 30000)
-
阻塞当前线程,直到进程的标准错误(stderr)有数据可读或超时。
-
msecs:超时时间(毫秒),默认 30 秒。
-
返回值:true 表示有数据可读,false 表示超时或错误。
-
-
waitForFinished(int msecs = 30000)
-
阻塞当前线程,直到外部进程结束或超时。它用于等待进程完成整个执行流程。
-
msecs:超时时间(毫秒),默认 30 秒,-1 表示无限等待。
-
返回值:true 表示进程结束,false 表示超时。
-
结果获取:结束后可通过 exitCode() 和 exitStatus() 获取信息。
-
-
全面控制能力:
-
终止控制:kill() 强制结束,terminate() 请求结束。
-
等待机制:waitForStarted() 确认启动,waitForReadyReadStandardOutput() 和 waitForReadyReadStandardError() 等待输出,waitForFinished() 等待结束。
-
-
-
设置进程环境/通道模式
QProcess 提供了方法来配置外部进程的运行环境,包括工作目录和环境变量。进程通道模式定义了 QProcess 如何处理外部进程的标准输出(stdout)和标准错误(stderr)通道。- setWorkingDirectory(const QString &dir)
- 设置外部进程的工作目录,即进程运行时的当前目录。
-
dir:工作目录的绝对路径(QString 类型)。
-
必须在启动前设置:只有在调用 start() 之前设置才生效。
-
可查询:通过 workingDirectory() 获取当前值。
- setEnvironment(const QStringList &environment)
- 设置外部进程的环境变量列表,覆盖默认继承的环境变量。
-
environment:环境变量列表,每项为 "key=value" 格式的字符串。
-
启动前设置:必须在 start() 之前调用。
- setProcessEnvironment(const QProcessEnvironment &environment)
-
设置外部进程的环境变量,使用 QProcessEnvironment 对象。
-
environment:QProcessEnvironment 对象,包含环境变量的键值对。
- env.insert("MY_VAR", "test"); // 添加或修改变量
- env.remove("UNWANTED_VAR"); // 删除变量
-
- setProcessChannelMode(QProcess::ProcessChannelMode mode)
- 设置进程的通道模式,决定 stdout 和 stderr 的处理方式。
-
mode:枚举值,可选:
-
QProcess::SeparateChannels:stdout 和 stderr 分开(默认)。
-
QProcess::MergedChannels:stdout 和 stderr 合并为一个输出流。
-
QProcess::ForwardedChannels:将输出转发到父进程的 stdout/stderr。
-
QProcess::DisabledChannels(已废弃):禁用输出(不推荐)。
-
-
setEnvironment() vs setProcessEnvironment()
方法
输入类型
默认环境变量
操作方式
setEnvironment()
QStringList
完全覆盖
直接指定全部
setProcessEnvironment()
QProcessEnvironment
可继承系统环境
增删改查
-
环境设置/通道模式
-
setWorkingDirectory() 指定运行目录,影响路径解析。
-
setEnvironment() 完全定义环境变量,适合自定义环境。
-
setProcessEnvironment() 灵活调整环境变量,基于系统环境。
-
setProcessChannelMode() 控制 stdout 和 stderr 的处理方式,适应不同输出需求。
-
- setWorkingDirectory(const QString &dir)
-
-
主要信号
QProcess 的信号机制是其异步操作的核心,允许开发者通过事件驱动的方式监控进程的状态变化和数据输出。这些信号与 Qt 的信号槽机制紧密集成,提供实时反馈。-
started() 信号在外部进程成功启动时发出,异步性:适合实时监控进程开始。
-
finished(int exitCode, QProcess::ExitStatus exitStatus)
-
信号在外部进程结束时发出,提供退出代码和退出状态。
-
exitCode:进程返回的退出代码(0 通常表示成功)。
-
exitStatus:退出状态(NormalExit 或 CrashExit)。
-
-
readyReadStandardOutput()
-
信号在外部进程的标准输出(stdout)有新数据可读时发出。
-
实时性:数据可用时立即触发,支持动态读取。
-
无参数:需手动读取(如 readAllStandardOutput())。
-
-
readyReadStandardError()
-
信号在外部进程的标准错误(stderr)有新数据可读时发出。
-
错误捕获:专门处理 stderr 数据。
-
实时响应:与 stdout 独立触发,支持分开处理。
-
需配合读取:信号本身不含数据,需调用 readAllStandardError()。
-
-
errorOccurred(QProcess::ProcessError error)
-
信号在进程启动或运行时发生错误时发出,提供具体的错误类型,帮助诊断问题。
-
error:错误类型枚举(FailedToStart、Crashed、Timedout 等)。
-
-
stateChanged(QProcess::ProcessState newState)
-
信号在进程状态发生变化时发出,提供新的状态值,帮助跟踪进程生命周期。
-
newState:新状态(NotRunning、Starting、Running)。
-
-
信号构成了 QProcess 的事件驱动核心
-
生命周期:started()、finished() 和 stateChanged() 监控进程开始、结束和状态变化。
-
数据输出:readyReadStandardOutput() 和 readyReadStandardError() 处理 stdout 和 stderr 数据。
-
异常处理:errorOccurred() 捕获错误。
-
-
-
进程通道模式详解
进程通道模式由 setProcessChannelMode(QProcess::ProcessChannelMode mode) 设置,控制 QProcess 如何处理外部进程的标准输出(stdout)和标准错误(stderr)。这些模式在进程启动前设置,影响输出数据的流向和读取方式。-
SeparateChannels
-
SeparateChannels 是默认模式,表示标准输出(stdout)和标准错误(stderr)保持独立,分别通过各自的通道输出。
-
stdout 数据通过 readAllStandardOutput() 或 readyReadStandardOutput() 读取。
-
stderr 数据通过 readAllStandardError() 或 readyReadStandardError() 读取。
-
两个通道互不干扰,数据不会混合。
-
-
MergedChannels
-
MergedChannels 将标准输出(stdout)和标准错误(stderr)合并为一个输出流,所有数据都通过 stdout 通道输出。
-
stdout 和 stderr 数据都由 readAllStandardOutput() 或 readyReadStandardOutput() 读取。
-
readAllStandardError() 和 readyReadStandardError() 无效(无数据)。
-
输出顺序可能因进程实现而异(不保证严格按时间顺序)。
-
-
ForwardedChannels
-
ForwardedChannels 将外部进程的 stdout 和 stderr 直接转发到父进程(即调用 QProcess 的程序)的标准输出和标准错误通道,通常显示在控制台上。
-
stdout 和 stderr 数据不会被 QProcess 捕获,而是直接输出到终端。
-
readAllStandardOutput() 和 readAllStandardError() 无数据可读。
-
类似运行命令时的原始行为。
-
-
通道模式(QProcess::ProcessChannelMode)
模式
行为
读取方式
使用场景
SeparateChannels
stdout 和 stderr 分开
分别读取 stdout 和 stderr
日志分离、调试
MergedChannels
stdout 和 stderr 合并到 stdout
仅读取 stdout(含全部数据)
统一输出、简单显示
ForwardedChannels
输出转发到父进程终端
无法读取,直接显示
调试、直观交互
-
-
同步与异步执行
QProcess 提供了两种主要的执行外部进程的方式:异步执行(start())和同步执行(execute())。这两种方式在执行流程、交互能力和适用场景上存在显著差异。-
异步执行 (start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite))
-
start() 以异步方式启动外部进程,调用后立即返回,进程在后台运行。开发者可以通过信号槽机制监控进程状态和输出,实现实时交互。
-
program:要运行的程序路径或命令。
-
arguments:传递给程序的参数列表。
-
mode:输入输出通道的打开模式(默认 ReadWrite)。
-
非阻塞:调用 start() 后,控制权立即返回给调用线程,进程在后台运行。
-
实时交互:支持通过 write() 写入 stdin,通过 readAllStandardOutput() 和 readAllStandardError() 读取输出。
-
信号驱动:依赖信号(如 started()、finished()、readyReadStandardOutput())处理进程事件。
-
生命周期管理:可以通过 kill() 或 terminate() 手动终止进程。
-
-
同步执行 (execute(const QString &program, const QStringList &arguments = QStringList()))
-
execute() 以同步方式运行外部进程,调用后线程会被阻塞,直到进程完成并返回退出代码。它是一个静态方法,适合简单的一次性任务。
-
program:要运行的程序路径或命令。
-
arguments:传递给程序的参数列表(可选)。
-
返回值:进程的退出代码(0 通常表示成功)。
-
阻塞:调用线程暂停,直到进程结束。
-
无交互:无法实时读取 stdout/stderr 或写入 stdin。
-
简单直接:无需信号槽,直接返回退出代码。
-
一次性:进程运行后自动清理,无需手动管理。
-
-
使用说明
特性
异步执行 (start())
同步执行 (execute())
执行方式
非阻塞,后台运行
阻塞,等待完成
交互性
支持 stdin/stdout/stderr 交互
无交互能力
返回值
无(通过信号获取结果)
退出代码
复杂度
需要信号槽管理
简单直接
适用场景
GUI、实时输出、复杂任务
短时任务、非 GUI、简单命令
资源管理
需手动控制(如关闭进程)
自动清理
-
-
高级用法
QProcess 不仅限于基本的进程启动和输出读取,还支持管道操作、通道自定义以及与网络功能的集成。这些高级用法扩展了其在多进程协作和跨系统交互中的应用。-
管道重定向
-
管道重定向允许将一个进程的输出(stdout)作为另一个进程的输入(stdin),实现多进程之间的数据流传递。
-
方法:setStandardOutputProcess(QProcess *destination)将当前进程的 stdout 重定向到目标进程的 stdin。
-
-
自定义通道模式
-
setStandardOutputFile(const QString &fileName):将 stdout 重定向到指定文件。
-
setStandardErrorFile(const QString &fileName):将 stderr 重定向到指定文件。
-
setStandardInputFile(const QString &fileName):从指定文件读取 stdin 数据。
-
文件重定向:输出直接写入文件而非程序缓冲区,输入从文件读取。
-
独立控制:stdout 和 stderr 可分别重定向到不同文件。
-
-
与网络结合
-
QProcess 可以与 Qt 的网络模块(如 QTcpSocket、QNetworkAccessManager)结合,通过外部进程处理网络数据,或将进程输出发送到网络。
-
进程输出到网络:读取进程输出,通过 socket 或 HTTP 发送。
-
网络数据到进程:从网络接收数据,写入进程 stdin。
-
数据桥接:QProcess 作为本地处理单元,网络模块负责远程通信。
-
异步性:结合 QProcess 的信号和网络的事件循环,实现非阻塞操作。
-
-
用法说明
高级用法
功能描述
关键方法/技术
使用场景
管道重定向
将一个进程的输出作为另一个进程的输入
setStandardOutputProcess()
数据处理链、多阶段任务
自定义通道模式
重定向输入输出到文件或设备
setStandardOutputFile()等
日志记录、静默执行、批量输入
与网络结合
进程与网络数据交互
QProcess +QTcpSocket
等网络类
远程命令、数据处理服务、分布式系统
-
-
错误处理
QProcess 在运行外部进程时可能会遇到各种错误,例如启动失败、执行异常或超时。Qt 提供了多种机制来检测和处理这些错误,包括信号、状态检查和输出分析。-
启动错误:启动错误发生在调用 start() 或 startDetached() 时,进程无法成功启动。
-
方法:调用 error() 返回 QProcess::FailedToStart,通过 errorString() 获取详细描述。
-
信号:errorOccurred(QProcess::FailedToStart) 信号触发。
-
-
执行错误
执行错误发生在进程启动后运行时出现问题,进程崩溃(Crash)或因非法操作终止。-
信号:errorOccurred(QProcess::Crashed) 信号触发。
-
方法:exitStatus() 返回 QProcess::CrashExit,error() 返回 QProcess::Crashed。
-
使用 readAllStandardError() 获取可能的错误信息。
-
-
超时错误
-
超时错误发生在等待进程事件(如启动、数据可读或结束)时超过指定时间。
-
方法:waitForStarted()、waitForFinished() 等返回 false,error() 返回 QProcess::Timedout。
-
信号:errorOccurred(QProcess::Timedout) 信号触发。
-
-
处理 errorOccurred() 信号
-
涵盖所有错误类型(启动、执行、超时等)。
-
全面性:捕获所有可能的错误类型。
-
实时性:错误发生时立即触发。
-
补充信息:结合 errorString() 获取详细描述。
-
-
检查退出代码和标准错误输出
-
退出代码(exitCode())和标准错误输出(stderr)是判断进程执行结果的重要依据。
-
退出代码:通过 finished() 信号或 exitCode() 获取。
-
标准错误:通过 readyReadStandardError() 信号或 readAllStandardError() 读取。
-
-
错误类型分类处理
错误类型
检测方法
常见原因
处理建议
启动错误
errorOccurred(QProcess::FailedToStart)
文件不存在、权限不足
检查路径和权限,记录错误
执行错误
errorOccurred(QProcess::Crashed)
进程崩溃、环境配置错误
检查参数和 stderr,调试崩溃原因
超时错误
waitFor*()返回false,QProcess::Timedout
进程卡死、执行时间过长
调整超时时间,必要时终止进程
信号处理
errorOccurred(QProcess::ProcessError)
各种错误
根据错误类型分类处理,记录日志
退出码/stderr
exitCode()、readAllStandardError()
进程逻辑错误、外部依赖缺失
分析退出码和 stderr,提示用户
-
测试代码
案例编号 | 主题 | 难度 | 涉及内容 | 适用场景 |
---|---|---|---|---|
1 | 基础使用 | 简单 | 启动、同步/异步、输出读取 | 初学、简单命令执行 |
2 | 交互式命令 | 中等 | 交互、信号、通道模式 | 动态输入输出、实时反馈 |
3 | 错误与状态监控 | 中等 | 信息获取、控制、错误处理、信号 | 健壮性任务、构建系统 |
4 | 管道与通道自定义 | 较难 | 管道、通道模式、高级用法 | 数据处理链、文件操作 |
5 | 与网络结合 | 复杂 | 异步、网络集成、高级用法 | 远程服务、分布式系统 |
案例 1:基础使用 - 运行简单命令并获取输出
运行一个简单的系统命令(如 dir 或 ls),获取其输出并显示。
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
#include <QtGlobal>
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv); // 添加事件循环支持扩展性
QProcess process;
// ======================
// 同步方式执行命令
// ======================
QString command;
QStringList arguments;
if (QSysInfo::productType() == "windows") {
command = "cmd.exe";
arguments << "/c" << "dir"; // 使用 cmd.exe 执行 dir
} else {
command = "ls";
// arguments << "-l"; // 示例参数,可选
}
int exitCode = QProcess::execute(command, arguments);
if (exitCode == 0) {
qDebug() << "Command executed successfully";
} else {
qDebug() << "Command failed with exit code:" << exitCode;
}
// ======================
// 异步方式获取输出
// ======================
process.start(command, arguments);
if (!process.waitForStarted()) {
qDebug() << "Failed to start:" << process.errorString();
return 1;
}
process.waitForFinished();
QString output = QString::fromLocal8Bit(process.readAllStandardOutput()); // 处理 Windows 本地编码
qDebug() << "Output:" << output.trimmed();
return app.exec();
}
// ======================
// console
// ======================
//Makefile
//QtCore
//main.moc
//main.o
//moc_EventObject.cpp
//moc_EventObject.o
//moc_SenderReceiver.cpp
//moc_SenderReceiver.o
//moc_predefs.h
//Command executed successfully
//Output: "Makefile\nQtCore\nmain.moc\nmain.o\nmoc_EventObject.cpp\nmoc_EventObject.o\nmoc_SenderReceiver.cpp\nmoc_SenderReceiver.o\nmoc_predefs.h"
案例 2:交互式命令 - 实时读取和输入
运行一个交互式命令行工具(如计算器 bc),实时读取输出并发送输入。
#include <QProcess>
#include <QDebug>
#include <QCoreApplication>
// ======================
// 主函数
// ======================
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv); // 添加事件循环支持异步信号
QProcess process;
// 设置通道模式为分开(默认)
process.setProcessChannelMode(QProcess::SeparateChannels);
// ======================
// 连接信号以实时读取输出
// ======================
QObject::connect(&process, &QProcess::readyReadStandardOutput, [&process]() {
qDebug() << "Result:" << process.readAllStandardOutput();
});
// ======================
// 根据操作系统选择合适的交互式进程
// ======================
#ifdef Q_OS_WIN
// Windows 使用 powershell.exe 执行计算
process.start("powershell.exe", QStringList() << "-NoProfile" << "-NoLogo" << "-Command" << "(2 + 3)");
#else
// Unix/Linux 使用 bc
process.start("bc");
process.waitForStarted();
// 发送计算指令
process.write("2 + 3\n"); // 输入表达式
process.write("quit\n"); // 退出 bc
#endif
process.waitForFinished();
return app.exec(); // 使用事件循环确保信号被处理
}
// ======================
// console
// ======================
//Result: "5\n" linux
//Result: "5\r\n" windows
案例 3:错误处理与状态监控 - 编译代码并分析结果
运行编译器(如 gcc),处理启动错误、执行错误,并检查退出代码和 stderr 输出。
#include <QProcess>
#include <QDebug>
#include <QObject>
// ======================
// 主函数
// ======================
int main(int argc, char *argv[]) {
Q_UNUSED(argc);
Q_UNUSED(argv);
QProcess process;
// ======================
// 设置工作目录
// ======================
process.setWorkingDirectory("/path/to/project");
// ======================
// 错误处理信号
// ======================
QObject::connect(&process, &QProcess::errorOccurred, [&process](QProcess::ProcessError error) {
qDebug() << "Error:" << process.errorString();
switch (error) {
case QProcess::FailedToStart:
qDebug() << "Failed to start";
break;
case QProcess::Crashed:
qDebug() << "Process crashed";
break;
default:
break;
}
});
// ======================
// 状态变化监控
// ======================
QObject::connect(&process, &QProcess::stateChanged, [](QProcess::ProcessState state) {
qDebug() << "State:" << (state == QProcess::NotRunning ? "Not Running" :
state == QProcess::Starting ? "Starting" : "Running");
});
// ======================
// 进程完成信号
// ======================
QObject::connect(&process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),[&process](int exitCode, QProcess::ExitStatus status) {
qDebug() << "Exit code:" << exitCode << "Status:" << (status == QProcess::NormalExit ? "Normal" : "Crashed");
if (exitCode != 0) {
qDebug() << "Errors:" << process.readAllStandardError();
}
});
// ======================
// 启动进程
// ======================
process.start("gcc", QStringList() << "nonexistent.c"); // 故意编译不存在的文件
process.waitForFinished();
return 0;
}
// ======================
// console
// ======================
//State: Starting
//State: Not Running
//Error: "chdir: No such file or directory"
//Failed to start
案例 4:管道与通道自定义 - 多进程协作
使用管道将 ls 的输出传递给 sort 排序,并将结果重定向到文件。
#include <QProcess>
#include <QDebug>
#include <QFile>
int main(int argc, char *argv[]) {
QProcess process1; // 源进程
QProcess process2; // 目标进程
// 设置管道:process1 的 stdout 到 process2 的 stdin
process1.setStandardOutputProcess(&process2);
// 设置通道模式和输出重定向
process2.setProcessChannelMode(QProcess::MergedChannels); // 合并 stdout 和 stderr
process2.setStandardOutputFile("sorted_output.txt"); // 输出到文件
// 启动进程
process1.start("ls", QStringList() << "-l");
process2.start("sort");//对内容进行排序
// 等待完成
process1.waitForFinished();
process2.waitForFinished();
// 读取文件内容
QFile file("sorted_output.txt");
if (file.open(QIODevice::ReadOnly)) {
qDebug() << "Sorted output:" << file.readAll();
file.close();
}
return 0;
}
// ======================
// console sorted_output.txt
// ======================
//-rw-r--r-- 1 user user 0 Apr 8 18:16 sorted_output.txt
//-rw-r--r-- 1 user user 4511 Mar 31 21:07 moc_EventObject.cpp
//-rw-r--r-- 1 user user 6851 Mar 31 20:10 moc_SenderReceiver.cpp
//-rw-r--r-- 1 user user 7428 Apr 4 00:02 main.moc
//-rw-r--r-- 1 user user 14725 Mar 31 20:09 moc_predefs.h
//-rw-r--r-- 1 user user 22585 Apr 8 18:16 Makefile
//-rw-r--r-- 1 user user 593248 Apr 8 18:14 main.o
//-rw-r--r-- 1 user user 611312 Mar 31 21:07 moc_EventObject.o
//-rw-r--r-- 1 user user 631336 Mar 31 20:10 moc_SenderReceiver.o
//-rwxr-xr-x 1 user user 371704 Apr 8 18:14 QtCore
//total 2228
案例 5:与网络结合 - 远程命令执行服务
构建一个简单的 TCP 服务器,接收客户端命令,通过 QProcess 执行并返回结果。
服务器端:.pro添加:QT += network
#include <QCoreApplication>
#include <QProcess>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
// ======================
// 主函数
// ======================
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
QTcpServer server;
// ======================
// 检查服务器是否启动
// ======================
if (!server.listen(QHostAddress::Any, 12345)) {
qDebug() << "Server failed to start:" << server.errorString();
return 1;
}
qDebug() << "Server running on port 12345";
// ======================
// 处理新连接
// ======================
QObject::connect(&server, &QTcpServer::newConnection, [&server]() {
QTcpSocket *client = server.nextPendingConnection();
if (!client) {
qDebug() << "Null client pointer";
return;
}
// ======================
// 为每个客户端创建独立的 QProcess 对象
// ======================
QProcess *process = new QProcess(client); // 绑定到 client 的生命周期
process->setProcessChannelMode(QProcess::SeparateChannels);
// ======================
// 客户端数据到达时执行命令
// ======================
QObject::connect(client, &QTcpSocket::readyRead, [client, process]() {
QByteArray commandData = client->readAll();
QString command = QString::fromUtf8(commandData).trimmed();
if (command.isEmpty()) {
qDebug() << "Empty command received";
client->write("Error: No command provided\n");
return;
}
// 解析命令和参数
QStringList parts = command.split(" ", Qt::SkipEmptyParts);
QString program = parts.takeFirst();
QStringList arguments = parts;
// 启动进程
process->start(program, arguments);
if (!process->waitForStarted(1000)) {
qDebug() << "Process failed to start:" << process->errorString();
client->write("Error: Failed to start process\n");
return;
}
});
// ======================
// 发送进程输出到客户端
// ======================
QObject::connect(process, &QProcess::readyReadStandardOutput, [client, process]() {
QByteArray output = process->readAllStandardOutput();
if (client->state() == QAbstractSocket::ConnectedState) {
client->write(output);
}
});
// ======================
// 发送错误输出
// ======================
QObject::connect(process, &QProcess::readyReadStandardError, [client, process]() {
QByteArray error = process->readAllStandardError();
if (client->state() == QAbstractSocket::ConnectedState) {
client->write("Error: " + error);
}
});
// ======================
// 进程结束时通知客户端
// ======================
QObject::connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), [client, process](int exitCode, QProcess::ExitStatus status) {
if (client->state() == QAbstractSocket::ConnectedState) {
client->write(QByteArray("Exit code: ") + QByteArray::number(exitCode) + "\n");
client->disconnectFromHost();
}
});
// ======================
// 客户端断开时清理
// ======================
QObject::connect(client, &QTcpSocket::disconnected, [client, process]() {
qDebug() << "Client disconnected";
process->deleteLater(); // 清理 process
client->deleteLater(); // 清理 client
});
});
return app.exec();
}
// ======================
// console
// ======================
//Server running on port 12345
//Client disconnected
客户端:.pro添加:QT += network
#include <QCoreApplication>
#include <QTcpSocket>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
QTcpSocket socket;
socket.connectToHost("localhost", 12345);
if (socket.waitForConnected(3000)) {
socket.write("ls -l\n"); // Linux 示例命令
socket.waitForReadyRead(5000);
qDebug() << "Response:" << socket.readAll();
socket.disconnectFromHost();
} else {
qDebug() << "Connection failed:" << socket.errorString();
}
return app.exec();
}
// ======================
// console
// ======================
//Response: "..."
QSharedMemory
-
:接下来,学习
QSharedMemory
类,它允许多个进程共享同一块内存区域,实现高效的数据交换。掌握如何创建、附加和分离共享内存段,以及处理同步和并发问题。
QSystemSemaphore
-
:然后,学习
QSystemSemaphore
类,它提供系统级的信号量,用于控制对共享资源的访问,确保多个进程之间的同步。了解如何使用信号量来避免竞争条件和死锁。
QLocalServer 和 QLocalSocket
-
:之后,学习
QLocalServer
和QLocalSocket
类,它们用于在同一台机器上的不同进程之间通过本地套接字进行通信。掌握如何创建本地服务器、监听连接,以及在客户端和服务器之间传递数据。
QSharedMemory
提供了进程间共享内存的访问,允许多个进程共享同一块内存区域。
七. 插件支持 (Plugin Support)
-
QPluginLoader
QPluginLoader
用于加载动态插件,使得应用程序能够在运行时加载和卸载插件。 -
QFactoryInterface
QFactoryInterface
是插件接口,插件可以实现特定功能,并通过该接口供应用程序使用。
八. 文本编解码 (Text Codecs)
-
QTextCodec
QTextCodec
用于文本编码和解码,支持多种字符集,如 UTF-8、GBK、ISO-8859-1 等。
九. 动态库加载 (Dynamic Library Loading)
-
QLibrary
QLibrary
用于加载动态链接库,并提供访问其导出函数的能力,支持跨平台的动态库管理。
十. 全局函数
-
qAbs
计算绝对值。
-
qDebug、qWarning、qCritical
调试和日志输出。
-
qInstallMsgHandler
安装消息处理程序。
-
qVersion
返回 Qt 版本。
-
qRegisterResourceData 和 qUnregisterResourceData:
资源数据管理。
十一. 其他实用工具
-
QUrl
URL 解析和生成。
-
QRandomGenerator
线程安全的随机数生成。
-
QCryptographicHas
加密哈希类(如 MD5、SHA-256)。
-
QJsonDocument、QJsonArray、QJsonObject、QJsonValue
JSON 处理:
-
QRegularExpression
Perl 兼容的正则表达式。
-
QSettings
跨平台应用设置存储。
-
QStandardPaths
返回标准目录路径。
-
QDebug
调试输出工具。
-
QCalendar
支持多种日历系统。
-
QDeadlineTimer
截止时间管理。