如何使用QT在Linux中读取文件设备
How to read a file device in Linux using Qt?
我正在处理一个基于QT5的小GUI,该GUI应显示Linux文件设备的数据流。为此,我选择了操纵杆输入。使用cat /dev/input/js0
,可以在终端上看到传入流。
使用C,您可以使用带有阻止读取或处理设备信号的循环读取此设备文件。但是我不用qt。
使用QT与设备文件进行交互的典型方法是什么?
基于@rodrigo的答案,这里有一个新的实现:
joystick.h
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <QObject>
#include <QFile>
#include <QSocketNotifier>
class Joystick
: public QObject
{
Q_OBJECT
QString fileName = "/dev/input/js0";
QFile *file;
QSocketNotifier *notifier;
public:
explicit Joystick(QObject *parent = nullptr);
~Joystick();
signals:
public slots:
void handle_readNotification(int socket);
};
#endif // JOYSTICK_H
joystick.cpp
#include "joystick.h"
Joystick::Joystick(QObject *parent)
: QObject(parent)
{
file = new QFile();
file->setFileName(fileName);
if( !file->exists() ){
qWarning("file does not exist");
return;
}
if( !file->open(QFile::ReadOnly) ){
qWarning("can not open file");
return;
}
notifier = new QSocketNotifier( file->handle(),
QSocketNotifier::Read,
this);
connect( notifier,
&QSocketNotifier::activated,
this,
&Joystick::handle_readNotification );
if( !notifier->isEnabled() ){
qInfo("enable notifier");
notifier->setEnabled(true);
}
qInfo("Joystick init ready");
}
void
Joystick::handle_readNotification(int /*socket*/)
{
static quint64 cnt=0;
qInfo("cnt: %d",cnt++);
if( !(file->isOpen()) ){
qWarning("file closed");
return;
}
char buf[16]; /* tested with different sizes */
if( file->read(buf,sizeof(buf)) ){
qInfo("read: %s",buf);
}
// QByteArray ba = file->readAll();
// qInfo("Data: %s", ba.data());
}
然后我运行,最后一个排名是cnt: 0
。看来read
或readAll
立即呼叫封锁。如果我评论读取电话,则计数器运行速度很快。这里是一个类似的帖子,这里是错误的?
最终解决方案
感谢Rodrigo!
joystick.h
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <QObject>
#include <QFile>
#include <QSocketNotifier>
class Joystick
: public QObject
{
Q_OBJECT
QString fileName = "/dev/input/js0";
QSocketNotifier *notifier;
int fd;
public:
explicit Joystick(QObject *parent = nullptr);
~Joystick();
signals:
void buttonPressed(quint8 number, qint16 value);
void axisMoved(quint8 number, qint16 value);
public slots:
void handle_readNotification(int socket);
};
#endif // JOYSTICK_H
joystick.cpp
#include "joystick.h"
#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>
Joystick::Joystick(QObject *parent)
: QObject(parent)
{
auto file = new QFile();
file->setFileName(fileName);
if( !file->exists() ){
qWarning("file does not exist");
return;
}
fd = open(fileName.toUtf8().data(), O_RDONLY|O_NONBLOCK);
if( fd==-1 ){
qWarning("can not open file");
return;
}
notifier = new QSocketNotifier( fd,
QSocketNotifier::Read,
this);
connect( notifier,
&QSocketNotifier::activated,
this,
&Joystick::handle_readNotification );
}
Joystick::~Joystick()
{
if( fd>=0 ){
close(fd);
}
}
void
Joystick::handle_readNotification(int /*socket*/)
{
struct js_event buf;
while( read(fd,&buf,sizeof(buf))>0 ){
switch (buf.type) {
case JS_EVENT_BUTTON:
emit buttonPressed(buf.number, buf.value);
break;
case JS_EVENT_AXIS:
emit axisMoved(buf.number, buf.value);
break;
}
}
}
通常使用工具包的轮询来源解决此问题。如果是QT,这是QSocketNotifier
。尽管它的名称(历史事故?(,但它可用于对任何文件描述符进行轮询,而不仅仅是插座。
因此,您只需使用open()
打开设备以获取文件描述符,然后在其上使用QSocketNotifier::Read
创建QSocketNotifier
。当要读取事件时,您将在其上获得activate()
信号。
替代解决方案,如果您仍然要使用Qfile而不是低级读/写功能:
auto file = new QFile(fileName);
...
// IMPORTANT: You must set the Unbuffered flag below
if(!file->open(QFile::ReadOnly | QFile::Unbuffered))
{
// handle error
}
auto fd = file.handle();
auto flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
// handle error
}
flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
if(flags == -1)
{
// handle error
}
auto notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
...
struct js_event buf;
while(file->read(&buf, sizeof(buf)) > 0)
{
// process data
}
相关文章:
- 使用新行和不使用新行读取文件
- 读取文件并输入到矢量中
- 读取文件的最后一行并输入到链接列表时出错
- 为什么在读取文件大小时文件IO速度会发生变化
- 读取文件时运行时的未知行为
- 如何逐行读取文件,每行中的内容都用空格分隔并将其写入新文件中
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- C++ 读取文件读取文件不正确
- 读取文件并将其存储在unordered_map中时出现问题
- 读取文件时无法使用 OpenMP 获得加速
- 使用istringstearm和get行缓慢读取文件
- 如何继续读取不同功能中的文件,而不是从头开始再次读取文件?
- 读取文件时引发异常
- 从标准输入读取文件后读取用户输入
- 在读取文件后重置句柄
- 如何在C++编译时读取文件?
- std::ifstream 在读取文件中最后一项时设置 eofbit,但仅在读取数值类型时发生
- 读取文件在第二次调用时返回INVALID_HANDLE
- 通过指针读取文件
- 逐行读取文件,并将数据插入变量和数组中