QFile、QDir学习---文件复制、获取文件、创建目录 以及QString args()用法

https://blog.51cto.com/u_15067237/2902336

QFile类提供读写文件的接口。QFile是一个I/O设备,用来读写文本文件、二进制文件和资源。QFile类希望文件路径的分隔符是’/’。而不是依赖操作系统,不支持其他的分隔符,例如’\’。

一、 copy()

bool QFile::copy(const QString &newName)

必须先创建一个file对象,再复制。
在复制文件之前,源文件会先被关闭。如果被复制的文件是一个符号链接(symlink),那么它所引用的文件会被复制,而不是链接本身。除了权限以外,其他的文件元数据都不会被复制。

如果成功复制文件,则返回 true;否则返回 false。请注意,如果 newName 已经存在一个同名文件,则 copy() 函数将返回 false,表示无法覆盖该文件,不会执行复制操作。

必须指定完整的路径和文件名

//创建一个QFileDialog来获取文件路径
QString path = QFileDialog::getOpenFileName(
            this,
            "OpenFile",
            "../",
            "TXT file(*.txt)");

//创建一个QFile对象
QFile file(path);
if(file.exists())
{
    //创建一个QFileDialog来获取保存文件路径
    QString SavePath = QFileDialog::getSaveFileName(
                this,
                "SaveFile",
                "../复制的文本",
                "TXT(*.txt)");

    bool isSaveOK = file.copy(SavePath);// 将 file 所指向的文件复制到 newName 指定的新位置
    if(isSaveOK)
    {
        ui->textEdit->setText("文件复制保存成功");
    }
    else
    {
        ui->textEdit->setText("文件复制保存失败");
    }

}
else
{
    ui->textEdit->setText("文件不存在");
    return;
}

bool QFile::copy(const QString & fileName, const QString & newName)
  1. 将当前指定的文件fileName复制到名为newName的文件中。
  2. 如果成功返回true;否则返回false。
  3. 注意,如果一个名为newName的文件已经存在,copy()返回false(即QFile不会覆盖它)。
  4. 源文件在复制之前关闭。
QString sourceFileName = QString("%1/%2").arg(imageFolderPath).arg(imageName);
QString destFileName = QString("%1/%2/%3/%4").arg(saveMainPath).arg(boxId).arg(slot).arg(imageName);
QFile::copy(sourceFileName,destFileName);

【补充:QString args()用法】

QString的arg()方法用于填充字符串中的%1,%2…为给定的参数。QString中有很多的元素可能是“%0”~“%99”,然后把arg( )中的值一个一个按顺序替换进去

QString m = tr("%1:%2:%3").arg("12").arg("60").arg("60");    // m = "12:60:60:

在这里插入图片描述

二、exists()

bool QFile::exists()

QFile::exists() const 是 Qt 中用于检查文件是否存在的函数,如果文件存在则返回 true;否则返回 false。

bool QFile::exists(const QString &fileName)

用于检查指定文件名的文件是否存在,如果文件存在则返回 true;否则返回 false

 QString saveMainPath = "D:/";
 QDir mainDir(saveMainPath);
 if(!mainDir.exists(saveMainPath)){//如果目录不存在就创建这个文件夹
     mainDir.mkdir(saveMainPath);
  }

三、创建文件目录

//创建image存放的目录
QString mainPath = "D:/a";
QDir mainDir(mainPath );
if(!mainDir.exists(mainPath )){
   mainDir.mkdir(mainPath );
 }
mainDir.cd(mainPath );

QString minPath = "soft" 
QDir minDir(minPath);
if(!minDir.exists(minPath)){
    mainDir.mkdir(minPath);
}
mainDir.cd(minPath);
QString path = QString("%1/%2").arg(mainPath).arg(minPath);
QFile currentFile(path);

四、获取文件夹下的所有文件、某一个文件

https://www.freesion.com/article/4784189397/

①获取指定目录下的所有图片

//获取文件夹下的文件名称
    QString imageFolderPath = "D:/svn1.1/code/mobileforensics/res/recoverydata/icon";
    QDir dir(imageFolderPath);//打开文件
    if (!dir.exists()) {
        return;
    }
    dir.setFilter(QDir::Files | QDir::NoSymLinks);
    QStringList filters;
    filters << "*.png" << "*.jpg";//只获取.png,.jpg为后缀的文件
    dir.setNameFilters(filters);
    QStringList allImageNameList = dir.entryList();//entryList()函数的参数分别代表:文件名称过滤器,文件属性过滤器,排序方式
    if (allImageNameList.count() <= 0)
    {
        return;
    }
    qDebug()<<tr("目录下的图片名称:")<<allImageNameList;

[补充:entryList的使用]

QStringList allNameList = dir.entryList(filters,QDir::Files | QDir::Readable,QDir::Time);//获取过滤后的所有的文件
if (allNameList .count() <= 0)
{
    return false;
}
//获取最新的文件
QString fileName;
fileName= allNameList .at(0);    
    

entryList参数说明:

第一个参数:筛选的条件

第二个参数:匹配条件
QDir::Files 列出文件
QDir::Dirs 列出与筛选器匹配的目录
QDir::AllDirs 列出所有目录;即不将过滤器应用于目录名
QDir::Readable 列出应用程序具有读取访问权限的文件
QDir::Writable 列出应用程序具有写访问权限的文件

第三个参数:排序方式
QDir::Name 按名称排序
QDir::Time 按时间排序(修改时间)
QDir::Size 按文件大小排序
QDir::Type 按文件类型(扩展名)排序
QDir::DirsFirst 首先放目录,然后放文件
QDir::Reversed 逆序

<think>问题分析: 用户描述了一个现象:在循环中多次使用QProcess::startDetached启动外部进程,当循环次数>=5时,软件可能启动失败。但如果在每次启动后加入Sleep(500)则情况改善。 可能的原因: 1. 资源限制:同时启动过多进程可能导致系统资源(如文件句柄、进程数等)耗尽,特别是当启动的进程需要大量资源时。 2. 端口冲突:如果启动的进程需要绑定端口,而端口尚未释放,可能导致后续进程启动失败。 3. 进程启动时间:启动进程需要时间,如果前一个进程还未完成初始化(例如绑定端口),下一个进程又启动,可能导致资源竞争。 4. 操作系统的进程创建限制:某些系统对短时间内创建大量进程有限制。 为什么Sleep(500)有改善? 通过每次启动后睡眠500毫秒,相当于减慢了启动速度,使得每个进程有足够的时间完成初始化(如绑定端口、分配资源等),从而避免了资源竞争和系统过载。 解决方案: 1. 使用QProcess管理进程,并等待进程启动完成(但startDetached是分离的,无法等待)。 2. 限制同时启动的进程数量,使用线程池或队列控制。 3. 增加启动间隔,如Sleep(但注意,Sleep会阻塞当前线程,在GUI线程中使用会导致界面卡顿)。 改进代码示例(使用QThread::msleep避免阻塞主线程): 注意:在GUI线程中睡眠会导致界面无响应,因此建议在子线程中执行启动操作。 更好的做法是使用QTimer来间隔启动进程,避免阻塞。 示例代码(在单独的线程中启动,并加入延迟): 但注意,如果启动的进程数量很大,建议使用队列和定时器来控制。 这里给出两种方案: 方案1:在子线程中启动,并加入延迟(不阻塞主线程) ```cpp #include <QThread> #include <QProcess> class ProcessStarter : public QThread { Q_OBJECT public: ProcessStarter(int count, ...) // 参数根据实际情况设计 { // 初始化参数 } void run() override { for (int i = 0; i < m_count; ++i) { QProcess::startDetached(m_exe, m_arguments); QThread::msleep(500); // 非阻塞式睡眠,但会阻塞当前线程(这个线程是工作线程) } } private: int m_count; QString m_exe; QStringList m_arguments; }; // 使用 ProcessStarter *starter = new ProcessStarter(5, exe, arguments); starter->start(); // 在后台启动 ``` 方案2:使用QTimer间隔启动(更推荐,不创建额外线程) ```cpp // 在类中定义 QTimer m_timer; int m_currentCount = 0; int m_totalCount = 10; // 总共要启动的进程数 QString m_exe; QList<QStringList> m_argumentsList; // 每个进程的参数可能不同 // 初始化 connect(&m_timer, &QTimer::timeout, this, &MyClass::startNextProcess); m_timer.start(500); // 每500毫秒启动一个 // 槽函数 void MyClass::startNextProcess() { if (m_currentCount >= m_totalCount) { m_timer.stop(); return; } QStringList args = m_argumentsList.at(m_currentCount); QProcess::startDetached(m_exe, args); m_currentCount++; } ``` 原因详细解释: 当循环中连续启动多个进程时,系统需要为每个进程分配资源。如果启动速度过快,可能导致: - 文件描述符耗尽:每个进程可能需要打开文件,系统有最大文件打开数的限制。 - 内存不足:每个进程都需要内存,同时启动过多可能导致内存不足,进程创建失败。 - 端口冲突:如果启动的进程需要绑定到同一个端口(或端口范围),而前一个进程还未绑定,下一个进程尝试绑定同一个端口就会失败。 - 进程表满:操作系统对进程数量有限制(特别是用户级别),短时间内创建大量进程可能导致无法创建新进程。 加入延迟后,每次启动之间有了间隔,系统有足够时间完成资源分配,前一个进程可能已经完成了初始化(例如绑定端口),从而避免了冲突。 建议: 1. 检查每个启动的进程是否独立,是否有可能共享同一个资源(如端口)而导致冲突。 2. 监控系统资源(如文件描述符数量、内存使用情况)以确定是否是资源耗尽。 3. 如果可能,重构启动的进程,使其可以接受配置参数,然后由一个主进程管理多个实例,而不是启动多个独立进程。 相关问题: §§相关问题§§: 1. 在Qt中,如何避免在循环中频繁启动外部进程导致的资源不足问题? 2. QProcess::startDetached和QProcess::start在资源管理上有何不同? 3. 在GUI程序中,如何在不阻塞主线程的情况下延迟执行任务? 4. 如何监控和诊断进程创建失败的问题?</think># 循环中多次启动外部进程的问题分析与解决 您描述的问题非常典型,涉及到进程启动的资源竞争和系统限制。我将详细解释原因并提供改进方案。 ## 问题原因分析 ### 1. 资源耗尽(文件描述符/句柄限制) ```cpp // 问题代码示例 for (int i = 0; i < 10; i++) { QProcess::startDetached(exe, args); } ``` **原因**: - 操作系统对每个进程有**文件描述符限制**(Linux默认1024,Windows默认512) - 每次启动外部进程需要: - 创建新进程描述符 - 打开标准输入/输出/错误管道 - 分配内存资源 - 快速连续启动多个进程可能导致资源耗尽 ### 2. 端口冲突 ```cpp QProcess::startDetached(exe, { "-server_port", QString::number(serverPort) // 所有进程尝试使用相同端口 }); ``` **原因**: - 如果多个进程尝试绑定到**相同端口** - TCP/UDP端口需要时间释放(TIME_WAIT状态) - 连续启动可能导致端口冲突 ### 3. 进程初始化时间 ```cpp // 进程启动时间线 t0: 启动进程1 t1: 启动进程2 (进程1尚未完成初始化) t2: 启动进程3 (进程1,2仍在初始化) ... ``` **原因**: - 每个外部进程需要**初始化时间**(加载库、分配内存等) - 如果前一个进程尚未完成初始化,后续进程可能因依赖资源冲突而失败 ### 4. 系统进程创建限制 - Linux:`pthread_create` 有限制(`ulimit -u`) - Windows:进程创建速率限制(默认约150个/秒) ## Sleep(500)为何有效 ```cpp for (int i = 0; i < 10; i++) { QProcess::startDetached(exe, args); QThread::msleep(500); // 添加500ms延迟 } ``` **改善原因**: 1. **资源释放时间**:给系统500ms回收前一个进程的资源 2. **端口释放**:TCP端口通常需要240ms(2*MSL)才能完全释放 3. **减少竞争**:避免多个进程同时竞争相同资源 4. **系统喘息**:给操作系统调度器时间处理新进程 ## 更优解决方案 ### 方案1:使用进程池(推荐) ```cpp #include <QThreadPool> #include <QRunnable> class ProcessLauncher : public QRunnable { public: ProcessLauncher(const QString& exe, const QStringList& args) : m_exe(exe), m_args(args) {} void run() override { QProcess process; process.start(m_exe, m_args); process.waitForStarted(); // 确保进程启动 } private: QString m_exe; QStringList m_args; }; // 使用方式 QThreadPool::globalInstance()->setMaxThreadCount(4); // 限制并发数 for (int i = 0; i < 10; i++) { ProcessLauncher* launcher = new ProcessLauncher(exe, args); QThreadPool::globalInstance()->start(launcher); } ``` ### 方案2:使用QTimer间隔启动 ```cpp int processCount = 0; int maxCount = 10; QTimer timer; QObject::connect(&timer, &QTimer::timeout, [&]() { if (processCount++ >= maxCount) { timer.stop(); return; } QProcess::startDetached(exe, args); }); timer.start(500); // 每500ms启动一个进程 ``` ### 方案3:端口动态分配 ```cpp int basePort = 8080; for (int i = 0; i < 10; i++) { int port = basePort + i; // 确保每个进程使用不同端口 QProcess::startDetached(exe, { "-server_port", QString::number(port) }); } ``` ### 方案4:使用信号量控制 ```cpp #include <QSemaphore> QSemaphore sem(4); // 允许4个并发 for (int i = 0; i < 10; i++) { QThreadPool::globalInstance()->start([=] { sem.acquire(); // 获取许可 QProcess process; process.start(exe, args); process.waitForStarted(); sem.release(); // 释放许可 }); } ``` ## 最佳实践建议 1. **资源监控**: ```cpp #ifdef Q_OS_LINUX #include <sys/resource.h> void checkResourceLimits() { rlimit limits; getrlimit(RLIMIT_NOFILE, &limits); qDebug() << "文件描述符限制:" << limits.rlim_cur << "/" << limits.rlim_max; } #endif ``` 2. **错误处理增强**: ```cpp qint64 pid; if (!QProcess::startDetached(exe, args, QDir::currentPath(), &pid)) { qCritical() << "进程启动失败:" << QProcess::errorString(); // 实现重试逻辑 } ``` 3. **性能优化**: ```cpp // 预加载可执行文件 QFile exeFile(exe); if (exeFile.open(QIODevice::ReadOnly)) { // 将可执行文件读入内存减少磁盘IO exeFile.close(); } ``` 4. **跨平台处理**: ```cpp #ifdef Q_OS_WIN // Windows需要额外处理 QProcess::startDetached("cmd.exe", {"/C", "start", exe}); #else QProcess::startDetached(exe, args); #endif ``` ## 根本原因总结 | 问题 | 原因 | 解决方案 | |------|------|----------| | 资源耗尽 | 文件描述符/内存限制 | 限制并发数 | | 端口冲突 | 相同端口快速重用 | 动态分配端口 | | 初始化冲突 | 进程同时访问共享资源 | 延迟启动 | | 系统限制 | 进程创建速率限制 | 控制启动频率 | | 依赖竞争 | 进程间依赖未就绪 | 添加启动确认 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值