玩龙天子 发表于 2016-12-1 11:56:47

QT在Windows中的技术总结(一):sqlite的备份还原功能(调用cmd命令模式)

  由于公司在需要做QT项目,用于为产品(51单片机的)连接电脑打印串口信息。
但我以前是学嵌入式的,只会用QT在linux下面写软件,但目前公司也只有我一个软件工程师,所以,我也只好在Windows下用QT编程了。。。
网上关于QT在Windows下编程的资料很少很少,唯一我找到真正正正详细描述的昨天也已经被我转到了这里。
貌似Windows下MFC才是王道,但也真真没时间学习,此文献给所以迫不得已在Windows下使用QT的同病相怜者。
由于项目还在进行中,所以各种技术总结也在持续进行中。

首先第一篇写一下这两天纠结了很久的,QT在Windows下调用cmd命令,实现SQLite的备份还原功能。

由于犯了一个超级无敌低级错误——漏了"\n",使我失败无数次,然后也发现N种方法。

1、最简单的方法,就是调用系统命令system()函数,不用定义任何对象,直接调用,但唯一的缺点就是运行的时候,会弹出一个黑框~

例子是用最简单的复制.db文件进行备份的。


  点击(此处)折叠或打开


[*]system("copy DataBase.db F:\Bak.db");


  
2、另外一种就是使用QProcess类,在Linux下是可以直接打命令运行的,但在Windows下貌似都没有反映,后来,先调了start个cmd出来,再write命令进去,就能运行了。

例子是调用sqlite3内部的命令

(注意必须有sqlite3.exe才能运行成功)

附上官网地址 http://www.sqlite.org/download.html  

选择 Precompiled Binaries for Windows 下的 

sqlite-shell-win32-x86-3071700.zip


  点击(此处)折叠或打开


[*]QProcess *Pro;

[*]Pro = new QProcess(this);
[*]QFileDialog * file = new QFileDialog(this);
[*]QString Dir = file->getExistingDirectory(this, tr("Open Directory"),"d:\\",
[*]                                             QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);//获取文件夹路径
[*]QStringList List = Dir.split("/");
[*]Dir = List[0];
[*]for(int i=1;i<List.count();i++)
[*]{
[*]    Dir += "\\\\" + List[i];
[*]}
[*]QString Text = QString("sqlite3.exe DataBase.db \".backup \\\"%1\\\\DB_Bak.db\\\" \" \n").arg(Dir);
[*]
[*]Pro->start("Cmd");
[*]Pro->waitForStarted();
[*]Pro->write(Text.toLatin1().data());
[*]Pro->closeWriteChannel();
[*]Pro->waitForFinished();
[*]Pro->close();


  需要主要的地方很多,我被卡在这里一个下午。
    首先是注意\n,另外是地址问题,明明是Windows下获取到的路径,结果地址上的连接符都是通过 / 连接的,本应该获取到的地址是D:\1\2,却变成了D:/1/2。这样的地址Windows下是不鸟你的,所以,我就通过split这个函数,先把地址用”/"截断,再用"\"组合起来,至于为什么是“\\\\"呢,这个我等下解释。虽然感觉QFileDialog是有成员函数可以将分隔号由"/"转成"\"的,但我找了半天都找不到,知道的麻烦告诉我一下吧~谢了!

   下面就来说说为什么是"\\\\"。首先看下Text这个即将传进cmd的指令。我在系统上直接运行的cmd命令是
     


[*]sqlite3.exe DataBase.db ".backup \"D:\\1\\2\\DB_Bak.db\" "

      其中\"是转义字符转成"这个不用多说了吧,同理\\也是转义字符,转成\,因为它们都在" "里面,当它们作为参数被读取的时候,都需要经过转义说明它们是字符。
    但是我们通过程序,用write()函数,把命令传进去的时候,整条命令都有" "包含,在传进去的时候就会进过一次转义,变成\\成了上面那个样子。如果只用\\,那么在传进去write的时候就会变成了\,所以在这里必须使用\\\\连续四个,才能保证经过两层转义,变成\。

    当准备好命令后,使用start()打开cmd终端,通过write()把命令写进去。这里也需要注意,write()的参数类型。


    终于成功实现功能的时候相当开心,但我发现把这条命令用在还原身上貌似不行。即使我在系统上直接运行cmd命令



[*]sqlite3.exe DB_Bak.db ".restore \"F:\\DataBase.db\""

      不仅不能实现备份还原(F:\DtatBase.db是存在的,只是里面的table都被我删了),并且DB_Bak.db里的表格都不见了!!我一直没找到原因,这个命令也是网上找到,知道原因请告诉我一下吧~
    所以用这种方式备份还原也是不可靠的,于是我又尝试了下把copy命令write到cmd中(请注意\n,system不用\n是因为它会自己加 write到cmd中,是不会自己加的)


  点击(此处)折叠或打开


[*]Pro->start("Cmd");

[*]Pro->waitForStarted();
[*]Pro->write(QString("copy DataBase.db %1\\DataBase.db \n").arg(Dir).toLatin1().data());
[*]Pro->closeWriteChannel();
[*]Pro->waitForFinished();
[*]Pro->close();


      注意哦,这里不需要两次转义上面的\\\\要改回\\才行哦!
    不过这种方式也是只能备份,因为在程序中你已经在打开这个数据库(即使你已经close,你的指针已经锁定它了),不可能拿另外一个东西覆盖它(总之我的不行,你可以自己试下)。

    所以这里介绍最后一种方法,能备份也能还原,其实比上面任何一种都简单= =
    这个方式在Linux下是很常用的,我以为Windows下不行的~



  点击(此处)折叠或打开


[*]void Interface::Backup()//备份

[*]{
[*]    QFileDialog * file = new QFileDialog(this);
[*]    QString Dir = file->getExistingDirectory(this, tr("Open Directory"),"d:\\",
[*]                                             QFileDialog::ShowDirsOnly|QFileDialog::DontResolveSymlinks);
[*]    QStringList List = Dir.split("/");
[*]    Dir = List[0];
[*]    for(int i=1;i<List.count();i++)
[*]    {
[*]        Dir += "\\\\" + List[i];
[*]    }
[*]    QString Text = QString("sqlite3.exe DataBase.db \".dump\" > %1\\a.sql\n").arg(Dir);
[*]    Pro->start("Cmd");
[*]    Pro->waitForStarted();
[*]    Pro->write(Text.toLatin1().data());
[*]    Pro->closeWriteChannel();
[*]    Pro->waitForFinished();
[*]    Pro->close();
[*]}


   
  点击(此处)折叠或打开


[*]void Interface::Import()//导入 

[*]{
[*]    QFileDialog * file = new QFileDialog(this);
[*]    QString Name = file->getOpenFileName(this, tr("Open DataBase"), "d:\\", tr("DataBase Files(*.sql)"));
[*]    QStringList List = Name.split("/");
[*]    Name = List[0];
[*]    for(int i=1;i<List.count();i++)
[*]    {
[*]        Name += "\\" + List[i];
[*]    }
[*]    QString Text = QString("sqlite3.exe DataBase.db < %1 \n").arg(Name);
[*]    Pro->start("Cmd");
[*]    Pro->waitForStarted();
[*]    Pro->write(Text.toLatin1().data());
[*]    Pro->closeWriteChannel();
[*]    Pro->waitForFinished();
[*]    Pro->close();
[*]
[*]}


      这方法貌似叫重定向吧,就是把数据库内容写入到文件中,还原的时候再从数据库里读出来,这方法挺好用的,程序很简单,上面的例子前面解读过了就不再累述了,导入和备份功能也差不多。

关于SQLite数据库在Windows下的使用(不使用sqlite3_exec()函数),将在下一篇中阐述。
页: [1]
查看完整版本: QT在Windows中的技术总结(一):sqlite的备份还原功能(调用cmd命令模式)