由于公司在需要做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()函数),将在下一篇中阐述。
?