QT中如何获取硬盘ID
如题
------解决方案--------------------
C/C++ code QString lpRootPathName = "C:\\";
LPTSTR lpVolumeNameBuffer=new TCHAR[12];//磁盘卷标
DWORD nVolumeNameSize=12;// 卷标的字符串长度
DWORD VolumeSerialNumber;//硬盘序列号
DWORD MaximumComponentLength;// 最大的文件长度
LPTSTR lpFileSystemNameBuffer=new TCHAR[10];// 存储所在盘符的分区类型的长指针变量
DWORD nFileSystemNameSize=10;// 分区类型的长指针变量所指向的字符串长度
DWORD FileSystemFlags;// 文件系统的一此标志
GetVolumeInformation((LPTSTR)lpRootPathNameutf16(),
lpVolumeNameBuffer, nVolumeNameSize,
&VolumeSerialNumber, &MaximumComponentLength,
&FileSystemFlags,
lpFileSystemNameBuffer, nFileSystemNameSize);
qDebug() << VolumeSerialNumber;
这是因为文件路径不对造成的,解决方法如下:
1、首先pro文件配置:Qt网络功能需要在pro文件增加网络库。
2、QTcpServer服务端建立的方法代码,如下图所示。
3、QTcpServer当有新客户端连接时,会发出QTcpServer::newConnection的信号方法代码。
4、客户端为主动连接方不需要监听,直接建立QTcpSocket代码。
5、最后通过connectToHost连接指定ip和端口,将socket的连接成功的信号与对应槽连接,当连接成功可以将自定义的标记位置为true。
1、Qt 作为一个通用开发库,提供了跨平台的文件 *** 作能力。文件 *** 作是应用程序必不可少的部分。
2、Qt5增加了QFileDevice类。途中所涉及的类及其用途简要说明如下:
· QFlie:访问本地文件或者嵌入资源;
· QTemporaryFile:创建和访问本地文件系统的临时文件;
· QBuffer:读写QByteArray;
· QProcess:运行外部程序,处理进程间通讯;
· QTcpSocket:TCP协议网络数据传输;
· QUdpSocket:传输 UDP 报文;
· QSslSocket:使用 SSL/TLS 传输数据;
· QFileDevice:新增加的类,提供了有关文件 *** 作的通用实现。
3、这其中,QProcess、QTcpSocket、QUdpSoctet和QSslSocket是顺序访问设备。所谓“顺序访问”,是指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节;QFile、QTemporaryFile和QBuffer是随机访问设备,可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针。
4、QFile主要提供了有关文件的各种 *** 作,比如打开文件、关闭文件、刷新文件等。我们可以使用QDataStream或QTextStream类来读写文件,也可以使用QIODevice提供的read()、readLine()、readAll()以及write()这样的函数。值得注意的是,有关文件本身的信息,比如文件名、文件所在目录的名字等,则是通过QFileInfo获取,而不是自己分析文件路径字符串。
5、举个例子,打开文件时,需要参数指定打开文件的模式:
Constant Value Description
QIODevice::NotOpen 0x0000 The device is not open
QIODevice::ReadOnly 0x0001 The device is open for reading
QIODevice::WriteOnly 0x0002 The device is open for writing
QIODevice::ReadWrite ReadOnly | WriteOnly The device is open for reading and writing
QIODevice::Append 0x0004 The device is opened in append mode, so that all data is written to the end of the file
QIODevice::Truncate 0x0008 If possible, the device is truncated before it is opened All earlier contents of the device are lost
QIODevice::Text 0x0010 When reading, the end-of-line terminators are translated to '\n' When writing, the end-of-line terminators are translated to the local encoding, for example '\r\n' for Win32QIODevice::Unbuffered 0x0020 Any buffer in the device is bypassed
一、文件下载
文件下载地址:
也可以下载我上传到网盘上的:
二、文件内容介绍
1下载到的文件为qextserialport-12win-alpha ,解压并打开后其内容如下。
(点击可以查看清晰大图)
下面分别介绍:
(1)doc文件夹中的文件内容是QextSerialPort类和QextBaseType的简单的说明,我们可以使用记事本程序将它们打开。
(2)examples文件夹中是几个例子程序,可以看一下它的源码,不过想运行它们好像会出很多问题啊。
(3)html文件夹中是QextSerialPort类的使用文档。
(4)然后就是剩下的几个文件了。其中qextserialenumeratorcpp及qextserialenumeratorh文件中定
义的QextSerialEnumerator类是用来获取平台上可用的串口信息的。不过,这个类好像并不怎么好用,而且它不是我们关注的重点,所以下面
就不再介绍它了。
(5)qextserialbasecpp和qextserialbaseh文件定义了一个QextSerialBase
类,win_qextserialportcpp和win_qextserialporth文件定义了一个Win_QextSerialPort
类,posix_qextserialportcpp和posix_qextserialporth文件定义了一个
Posix_QextSerialPort类,qextserialportcpp和qextserialporth文件定义了一个
QextSerialPort类。这个QextSerialPort类就是我们上面所说的那个,它是所有这些类的子类,是最高的抽象,它屏蔽了平台特征,
使得在任何平台上都可以使用它。
2几个类的简单介绍。
下面是这几个类的关系图。
可以看到它们都继承自QIODevice类,所以该类的一些函数我们也可以直接来使用。图中还有一个QextBaseType类,其实它只是一个标
识,没有具体的内容,它用来表示Win_QextSerialPort或Posix_QextSerialPort
中的一个类,因为在QextSerialPort类中使用了条件编译,所以QextSerialPort类既可以继承自
Win_QextSerialPort类,也可以继承自Posix_QextSerialPort类,所以使用了QextBaseType来表示。这一点
我们可以在qextserialporth文件中看到。再说QextSerialPort类,其实它只是为了方便程序的跨平台编译,使用它可以在不同的
平台上,根据不同的条件编译继承不同的类。所以它只是一个抽象,提供了几个构造函数而已,并没有具体的内容。在qextserialporth文件中的
条件编译内容如下:
#ifdef_TTY_POSIX_
#include“posix_qextserialporth”
#define QextBaseTypePosix_QextSerialPort
#else
#include“win_qextserialporth”
#define QextBaseTypeWin_QextSerialPort
#endif
所以,其实我们没有必要使用这个类,直接使用Win_QextSerialPort或Posix_QextSerialPort就可以了。当然如果
你想使用这个类,实现同样的源程序可以直接在Windows和Linux下编译运行,那么一定要注意在Linux下这里需要添加
#define _TTY_POSIX_ 。而我们这里为了使得程序更明了,所以没有使用该类,下面也就不再介绍它了。
QextSerialBase类继承自QIODevice类,它提供了 *** 作串口所必需的一些变量和函数等,而
Win_QextSerialPort和Posix_QextSerialPort均继承自QextSerialBase
类,Win_QextSerialPort类添加了Windows平台下 *** 作串口的一些功能,Posix_QextSerialPort类添加了
Linux平台下 *** 作串口的一些功能。所以说,在Windows下我们使用Win_QextSerialPort类,在Linux下我们使用
Posix_QextSerialPort类。
3在QextSerialBase类中还涉及到了一个枚举变量QueryMode。
它有两个值Polling和EventDriven
。QueryMode指的是读取串口的方式,下面我们称为查询模式,我们将Polling称为查询方式Polling,将EventDriven称为事件驱动方式。
事件驱动方式EventDriven就是使用事件处理串口的读取,一旦有数据到来,就会发出readyRead()信号,我们可以关联该信号来读取串口的数据。在事件驱动的方式下,串口的读写是异步的,调用读写函数会立即返回,它们不会冻结调用线程。
而查询方式Polling则不同,读写函数是同步执行的,信号不能工作在这种模式下,而且有些功能也无法实现。但是这种模式下的开销较小。我们需要自己建立定时器来读取串口的数据。
在Windows下支持以上两种模式,而在Linux下只支持Polling模式。
三、小结。
这里讲了这么多,最后要说的只是,我们在Qt中使用这个类编写串口程序,根据平台的不同只需要分别使用四个文件。
在Windows下是:
qextserialbasecpp和qextserialbaseh
以及win_qextserialportcpp和win_qextserialporth
在Linux下是:
qextserialbasecpp和qextserialbaseh
以及posix_qextserialportcpp和posix_qextserialporth
而在Windows下我们可以使用事件驱动EventDriven方式,也可以使用查询Polling方式,但是在Linux下我们只能使用查询Polling方式。
第二部分 在Windows下编写串口通信程序
我们的环境是Windowsxp,Qt463及Qt Creator20。
第一,下面我们首先使用事件驱动来实现串口通信。
1新建工程。
我们在QtCreator中新建Qt Gui工程,命名为myCom,Base Class选择QWidget。
2添加文件。
我们将那四个文件添加到工程文件夹中。如下图。
然后我们将这四个文件添加到工程中,在Qt
Creator的工程列表中的工程文件夹上点击鼠标右键,在d出的菜单中选择“AddExisting Files”菜单。如下图。
我们在d出的对话框中选中四个文件,按下“打开”按钮即可,如下图。
最终工程文件列表如下图。
3更改界面。
我们将界面设计如下。
其中的TextBrowser 部件用来显示接收到的数据,Line Edit部件用来输入要发送的数据,Push
Button按钮用来发送数据。我们保持各部件的属性为默认值即可。
4 我们在widgeth文件中进行对象及函数声明。
添加头文件包含:#include“win_qextserialporth”
然后在private中声明对象:Win_QextSerialPort myCom;
声明私有槽函数:
private slots:
voidon_pushButton_clicked(); //”发送数据”按钮槽函数
void readMyCom(); //读取串口
5在widgetcpp文件中进行更改。
在构造函数中添加代码,完成后,构造函数内容如下:
Widget::Widget(QWidgetparent) :
QWidget(parent),
ui(newUi::Widget)
{
ui->setupUi(this);
myCom=
new Win_QextSerialPort(“COM1″,QextSerialBase::EventDriven);
//定义串口对象,指定串口名和查询模式,这里使用事件驱动EventDriven
myCom->open(QIODevice::ReadWrite);
//以读写方式打开串口
myCom->setBaudRate(BAUD9600);
//波特率设置,我们设置为9600
myCom->setDataBits(DATA_8);
//数据位设置,我们设置为8位数据位
myCom->setParity(PAR_NONE);
//奇偶校验设置,我们设置为无校验
myCom->setStopBits(STOP_1);
//停止位设置,我们设置为1位停止位
myCom->setFlowControl(FLOW_OFF);
//数据流控制设置,我们设置为无数据流控制
myCom->setTimeout(500);
//延时设置,我们设置为延时500ms,这个在Windows下好像不起作用
connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));
//信号和槽函数关联,当串口缓冲区有数据时,进行读串口 *** 作
}
实现槽函数:
void Widget::readMyCom()//读取串口数据并显示出来
{
QByteArray
temp = myCom->readAll();
//读取串口缓冲区的所有数据给临时变量temp
ui->textBrowser->insertPlainText(temp);
//将串口的数据显示在窗口的文本浏览器中
}
voidWidget::on_pushButton_clicked() //发送数据
{
myCom->write(ui->lineEdit->text()toAscii());
//以ASCII码形式将数据写入串口
}
6此时,我们运行程序,效果如下。
可以看到,已经成功完成通信了。
(注:我们这里下位机使用的是单片机,它使用串口与计算机的COM1相连。单片机上运行的程序的功能是,接收到一个字符便向上位机发送一个字符串然后发送接收到的字符。)
两个重要问题的讲解:
一、关于数据接收。
我们想在程序中对接收的数据进行控制,但是readyRead()信号是一旦有数据到来就发射的,不过我们可以使用bytesAvailable()函数来检查已经获得的字节数,从而对数据接收进行控制。
(1)我们在widgetcpp中添加头文件包含:#include
然后在读串口函数中添加一行代码,如下:
void Widget::readMyCom() //读取串口数据并显示出来
{
qDebug()
<< “read:
“<<myCom->bytesAvailable()<<”bytes”;
//我们输出每次获得的字节数
QByteArray
temp = myCom->readAll();
ui->textBrowser->insertPlainText(temp);
}
运行程序,效果如下:
可以看到,我们获取的数据并不是一次获得的。
(2)利用上面的结论,我们可以让串口缓冲区拥有了一定的数据后再读取。
void Widget::readMyCom()
{
if(myCom->bytesAvailable()>=8 )
//如果可用数据大于或等于8字节再读取
{
qDebug()
<< “read:
“<<myCom->bytesAvailable()<<”bytes”;
QByteArray
temp = myCom->readAll();
ui->textBrowser->insertPlainText(temp);
}
}
运行程序,效果如下:
我们发送了两次数据,可以看到,这样实现了每8个字节读取一次,而最后剩余的不够8个字节的数据将会和后面的数据一起读出。
然后我们将8改为3,发送一次数据,效果如下:
改为7,发送两次数据,效果如下:
改为11,发送两次数据,效果如下:
改为17,发送三次数据,效果如下:
重要结论:我们发送一次数据,应该获得37字节的数据,然后我们对比上面的结果,发现了什么?是的,其实串口每次读取8字节的数据放到缓冲区,只有
数据总数小于8字节时,才会读取小于8字节的数据。为了再次验证我们的结论,我们可以将上面程序中的“>=”改为“==”,那么只有8的倍数才能读
取数据(当然这里37也可以),你可以测试一下。
关于接收数据方面,可以根据你自己的需要再去进行研究和改进,这里只是抛砖引玉。
二、关于发送数据。
我们也可以使用函数获取要发送的数据的大小,这里有个bytesToWrite()可以获取要发送的字节数。例如将发送数据更改如下:
voidWidget::on_pushButton_clicked() //发送数据
{
myCom->write(ui->lineEdit->text()toAscii());
qDebug()
<< “write:
“<<myCom->bytesToWrite()<<”bytes”;
//输出要发送的字节数
}
运行后效果如下:
当然,对于要发送的数据的大小我们不是很关心,而且它还有很多方法可以实现,这个还有个bytesWritten()信号函数来获取已经发送的数据的大小,不过好像它不是很好用。这里将它们提出来,只是供大家参考而已。
第二,使用查询方式Polling来实现串口通信。
这里再次说明,Polling方式是不能使用readyRead()信号的,所以我们需要自己设置定时器,来不断地读取缓冲区的数据。
1我们在widgeth中声明一个定时器对象。
添加头文件包含:#include
添加private变量:QTimer readTimer;
2我们在widgetcpp文件中的构造函数中更改。
(1)将串口定义更改为:
myCom =
newWin_QextSerialPort(“COM1″,QextSerialBase::Polling);
//定义串口对象,指定串口名和查询模式,这里使用Polling
(2)定义定时器,并将以前的关联更改为定时器的关联。
readTimer = newQTimer(this);
readTimer->start(100);
//设置延时为100ms
connect(readTimer,SIGNAL(timeout()),this,SLOT(readMyCom()));
//信号和槽函数关联,延时一段时间,进行读串口 *** 作
3此时运行程序,便可以正常收发数据了。
重点:关于延时问题。
上面的程序中可以进行数据的接收了,但是好像中间的延时有点长,要等一会儿才能收到数据,而且即便我们将定时器改为10ms
也不行。问题在哪里呢?其实真正控制串口读写时间的不是我们的定时器,而是延时timeout。我们在构造函数中设置了延时:
myCom->setTimeout(500);
//延时设置,我们设置为延时500ms
我们前面说延时并不起作用,那是因为是在事件驱动的情况下,一旦有数据到来就会触发readyRead()信号,所以延时不起作用。但是现在,真正
控制串口读写数据间隔的就是这个函数。这里值得注意,我们现在所说的串口读写是指底层的串口读写,从上面的程序中我们也可以看到,我们每隔100ms去读
串口,确切地说,应该是去读串口缓冲区。而timeout才是正真的读取串口数据,将读到的数据放入串口缓冲区。所以如果timeout时间很长,即便我
们的定时器时间再短,也是读不到数据的。所以我们这里需要将timeout设置为较小的值,比如10。我们更改代码:
myCom->setTimeout(10);
这样再运行程序,我们就可以很快地获得数据了。
关于数据接收:事件驱动那里的结论依然有用,不过这里更多的是靠读取的时间间隔来控制。
关于发送数据:这时bytesToWrite()函数就不再那么好用了。
第三部分 在Linux下编写串口通信程序
我这里的环境是Ubuntu1004,Qt 463和Qt Creator20
。上面已经提到,在Linux下只能使用Polling的方式读取串口数据,所以我们将上面Windows下的应用Polling的程序在Linux下重
新编译。我们使用Qt Creator打开该工程,然后进行下面的 *** 作。
1文件替换。
将工程中的win_qextserialportcpp和win_qextserialporth文件替换成posix_qextserialportcpp和posix_qextserialporth文件。
(1)我们先删除工程中的win_qextserialportcpp和win_qextserialporth文件。
在工程列表中用鼠标右击win_qextserialporth,然后选择“Remove File”选项。如下图。
在d出的对话框中我们选中“Deletefile permanently”选项,确保删除了工程文件夹中的文件。如下图。
然后我们使用同样的方法删除win_qextserialportcpp文件。
(2)我们按照Windows下添加文件的方法,向工程中添加posix_qextserialportcpp和posix_qextserialporth文件。最终工程文件列表如下。
2设置编码。
(这是因为两个系统使用的默认编码不同造成的,如果你那里没有该问题,可以跳过这一步)
现在我们打开widgetcpp文件,发现中文出现乱码,而且无法编辑。在编辑器最上面有一个**提示条和一个“Select
Encoding”按钮,我们点击该按钮。如下图。
在d出的对话框中我们选择“GB2312”。按下“Reload with Encoding”按钮,中文就可以正常显示了。
3更改程序。
在widgeth文件中:
将以前的#include“win_qextserialporth”更改为#include“posix_qextserialporth”
将以前的Win_QextSerialPortmyCom;更改为Posix_QextSerialPortmyCom;
在widgetcpp文件中:
将以前的myCom= new
Win_QextSerialPort(“COM1″,QextSerialBase::Polling);
更改为:myCom= new
Posix_QextSerialPort(“/dev/ttyS0″,QextSerialBase::Polling);
(这里一定要注意串口名称的写法。)
4下面我们运行程序。
这时可能会出现以下提示。
错误是说一个函数的调用出现了问题。我们点击该错误,定位到出错的位置,然后将那个函数中的第一个参数删除即可。如下图。
5再次运行程序,这时已经可以正常运行了。
6小结
可以看到将Windows下的串口程序在Linux下重新编译是很简单的,我们只需要替换那两个文件,然后更改一下头文件包含,对象定义和串口名即可。
先说明一下粘包的概念:发送时是两个单独的包、两次发送,但接收时两个包连在一起被一次接收到。在以前WinCE下Socket编程,确实也要处理粘包的问题,没想到在Android下也遇到了。首先想从发送端能否避免这样的问题,例如:(1)调用强制刷数据完成发送的函数;(2)设置发送超时。1先试了调用flush()函数,但运行后现象依旧2设置发送超时是Windows平台的做法,但在Android平台下是否有类似的设置呢?查看Socket类的实现代码:javanetsocketsocketclass文件后发现,还是有函数可以完成这样的设置的。请看如下函数和变量的说明:[java]viewplaincopy/Setsthissocket's{@linkSocketOptions#TCP_NODELAY}option/publicvoidsetTcpNoDelay(booleanon)throwsSocketException{checkOpenAndCreate(true);implsetOption(SocketOptionsTCP_NODELAY,BooleanvalueOf(on));}和[java]viewplaincopy/
是服务器的端口没有打开。
1、首先pro文件配置:Qt网络功能需要在pro文件增加网络库。
2、QTcpServer服务端建立的方法代码,如下图所示。
3、QTcpServer当有新客户端连接时,会发出QTcpServer::newConnection的信号方法代码。
4、客户端为主动连接方不需要监听,直接建立QTcpSocket代码。
5、最后通过connectToHost连接指定ip和端口,将socket的连接成功的信号与对应槽连接,当连接成功可以将自定义的标记位置为true。
注意事项:
int main()
{
Py_Initialize(); // 初始化// 将Python工作路径切换到待调用模块所在目录,一定要保证路径名的正确性string chdir_cmd = string("syspathappend(\'/xxxxxxx/')");
// 加载模块PyObject moduleName = PyString_FromString("xx"); //模块名,不是文件名PyObject pModule = PyImport_Import(moduleName);
// 加载函数PyObject pv = PyObject_GetAttrString(pModule, "xxx");// 调用函数PyObject pRet = PyObject_CallObject(pv, xxx);
以上就是关于qt如何获取硬盘序列号全部的内容,包括:qt如何获取硬盘序列号、Qt Socket网络编程 服务器端提示QIODevice::read (QTcpSocket): device not open,但是与客户端连接成功、qt文件读取等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)