linux+QT实现文件夹拷贝并附带进度功能

哎,半年不更博了,惭愧。从去年9月份开始,由于公司需要,转成了web app开发。直到年后回来才又回到嵌入式开发。学习web app开发过程中,也深深爱上了前端技术。那种敏捷开发自然是嵌入式不能比的,有段时间甚至感到还是app开发比较接地气,嵌入式大半年做不出一个产品,做出来还可能是面向某个领域的小众产品。不过从年后回来开始调wifi,又感觉技术上还是嵌入式比较有成就感,当然,技术无高低,哪项技术都不容易。学习web app时候一直没敢写博客,主要是因为自己也在学习阶段,怕水平太低误导群众。不过经过半年学习,我也算是踏进了半只脚的前端了,以后也会记录写web相关的内容。当然,还是以我熟悉的嵌入式为主啦。

废话不多说,开始正式新旅程吧。前阵子借助wpa_supplicant库实现了模拟手机wifi的连接程序,可谓是步步荆棘。这个待我好好整理后再发出来。这次先记录一个很小的功能—在linux平台的qt环境下实现文件夹拷贝并且带进度显示的几种方案

项目需求是实现一个自升级功能,其实就是用新的文件夹内容覆盖原来的,但是需要有进度显示。

  • 纯用系统命令

首先想到的就是借助Linux本身的cp命令啦,这个复制是没什么问题的,但是进度怎么拿到就是问题了。于是去查看cp的帮助信息,发现并没有拷贝进度相关的反馈。
然后笔者又去网上搜“linux 拷贝 进度”等关键词,搜到下面一篇文章:
http://www.veryhuo.com/a/view/18239.html
文中提到一个新的命令:rsync,用法如下:

$ rsync --progress a.exe a1.exe
a.exe
    20461680 100%   38.35MB/s    0:00:00 (xfer#1, to-check=0/1)

sent 20464246 bytes  received 31 bytes  13642851.33 bytes/sec
total size is 20461680  speedup is 1.00

笔者把a.exe复制成a3,命令下面的是输出信息。加了progress 选项输出内容还是非常详细的,包括进度,速度等。进度和速度都是不断变化的。所以只要提取命令的输出信息即可得到拷贝的进度。那么如何得到linux命令的反馈信息呢?这里我们可以使用linux的管道–pipe来实现。提供一段参考代码:

char num[5];
char command[100] = "rsync --progress a.zip a4";

int main()
{
    char buf[200];
    FILE *pipe;
    char *point;

    if((pipe = popen(command, "r")) == NULL)
    {
        printf("err popen");
        return -1;
    }

    while(1){
        if(fgets(buf, 100, pipe) != NULL)
        {
            buf[strlen(buf)-1] = '\0';
            if(point = strstr(buf, "%")){
                printf("%s\n", buf);  //buf里存的就是反馈信息                    
            }
        }
        else
        {
            break;
        }   
        usleep(2);
    }

    pclose(pipe);
}

剩下的就很简单了,只要提取%前面的数字就可以了,这里推荐使用正则表达式。
本以为做到这里就能实现了,结果使用这个命令拷贝文件夹时候发现它并不是输出整体的进度,而是输出每个文件的拷贝进度,这样肯定是不符合我们需求的。所以,这种方案只适合单个文件,并不适合文件夹。

  • 命令+线程

既然纯用命令不行,笔者又想了个迂回方案。用cp+线程实现。具体思想如下:

  1. 先记录待拷贝文件夹总大小
  2. 执行cp命令开始拷贝
  3. 开始拷贝后立刻启动一个线程,线程工作就是不停计算拷贝的文件夹大小,然后和记录的总大小计算进度,返回给主进程处理。

这里有个点就是计算文件夹大小,可以用递归算法来实现。提供一段qt的参考代码:

quint64 ProgressThread::du(const QString &path)
{
    QDir dir(path);
    quint64 size = 0;
    foreach (QFileInfo fileInfo, dir.entryInfoList(QDir::Files)) 
    {
        size += fileInfo.size();
    }
    foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        size += du(path + QDir::separator() + subDir);
    }
    return size;
}

path是待文件夹路径,实测过程中还有一个问题,由于cp命令是阻塞式,所以是以先执行命令,后开启统计线程的顺序执行,会造成拷贝完了以后线程才启动。所以可以先开启线程,再执行拷贝,当然最好的方案应该是两个操作都处理成线程,这样不用担心阻塞问题,还不会影响QT的UI响应。

  • 不借助命令

也就是纯程序实现了,这个无非是把cp的命令转换为程序实现,基本上就是递归拷贝,然后每拷贝完一个文件调用上面的统计程序进行计算拷贝进度。笔者没有亲测,只是预想了方案,当然,论灵活性当然是这个方案最高。但是没必要再造轮子不是吗,第二种方案还是比较简单可行的。

你可能感兴趣的:(开发辅助)