- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在使用 Qt 5.2.1 来实现一个从文件(可能是几个字节到几 GB)中读取数据并以依赖于每个字节的方式可视化该数据的程序。我这里的示例是一个十六进制查看器。
一个对象进行读取,并在读取新数据 block 时发出信号 dataRead()
。信号携带一个指向 QByteArray
的指针,如下所示:
void FileReader::startReading()
{
/* Object state code here... */
{
QFile inFile(fileName);
if (!inFile.open(QIODevice::ReadOnly))
{
changeState(STARTED, State(ERROR, QString()));
return;
}
while(!inFile.atEnd())
{
QByteArray *qa = new QByteArray(inFile.read(DATA_SIZE));
qDebug() << "emitting dataRead()";
emit dataRead(qa);
}
}
/* Emit EOF signal */
}
查看器将其 loadData
插槽连接到此信号,这是显示数据的函数:
void HexViewer::loadData(QByteArray *data)
{
QString hexString = data->toHex();
for (int i = 0; i < hexString.length(); i+=2)
{
_ui->hexTextView->insertPlainText(hexString.at(i));
_ui->hexTextView->insertPlainText(hexString.at(i+1));
_ui->hexTextView->insertPlainText(" ");
}
delete data;
}
第一个问题是,如果按原样运行,GUI 线程将变得完全无响应。所有 dataRead()
信号都将在 GUI 重绘之前发出。
(full code 可以运行,当你使用大于 1kB 左右的文件时,你会看到这种行为。)
根据对我的论坛帖子的回复 Non-blocking local file IO in Qt5以及另一个 Stack Overflow 问题的答案 How to do async file io in qt? ,答案是:使用线程。但是,这些答案都没有详细说明如何对数据本身进行洗牌,也没有详细说明如何避免常见错误和陷阱。
如果数据很小(大约一百个字节),我会用信号发送它。但在文件大小为 GB 的情况下(编辑)或者如果文件位于基于网络的文件系统上,例如。 NFS、Samba 共享,我不希望 UI 仅仅因为读取文件 block 而锁定。
第二个问题是,在发射器中使用 new
和在接收器中使用 delete
的机制似乎有点天真:我有效地使用整个堆作为跨线程队列。
问题 1:Qt 是否有更好/惯用的方法来跨线程移动数据同时限制内存消耗?它有线程安全队列或其他可以简化整个事情的结构吗?
问题 2:我有自己实现线程等吗?我不太喜欢重新发明轮子,尤其是在内存管理和线程方面。是否有更高级别的构造已经可以做到这一点,比如网络传输?
最佳答案
首先,您的应用中根本没有任何多线程。你的FileReader
类是QThread
的子类,但并不意味着所有的FileReader
方法都会在另一个线程中执行。事实上,您的所有操作都在主 (GUI) 线程中执行。
FileReader
应该是 QObject
而不是 QThread
子类。然后,您创建一个基本的 QThread
对象,并使用 QObject::moveToThread
将您的工作人员(阅读器)移动到它。您可以阅读有关此技术的信息 here .
确保您已使用 qRegisterMetaType
注册了 FileReader::State
类型。这是 Qt 信号槽连接跨不同线程工作所必需的。
一个例子:
HexViewer::HexViewer(QWidget *parent) :
QMainWindow(parent),
_ui(new Ui::HexViewer),
_fileReader(new FileReader())
{
qRegisterMetaType<FileReader::State>("FileReader::State");
QThread *readerThread = new QThread(this);
readerThread->setObjectName("ReaderThread");
connect(readerThread, SIGNAL(finished()),
_fileReader, SLOT(deleteLater()));
_fileReader->moveToThread(readerThread);
readerThread->start();
_ui->setupUi(this);
...
}
void HexViewer::on_quitButton_clicked()
{
_fileReader->thread()->quit();
_fileReader->thread()->wait();
qApp->quit();
}
这里也没有必要在堆上分配数据:
while(!inFile.atEnd())
{
QByteArray *qa = new QByteArray(inFile.read(DATA_SIZE));
qDebug() << "emitting dataRead()";
emit dataRead(qa);
}
QByteArray
使用 implicit sharing .这意味着当您以只读模式跨函数传递 QByteArray
对象时,其内容不会被一次又一次地复制。
将上面的代码改成这样,忘记手动内存管理:
while(!inFile.atEnd())
{
QByteArray qa = inFile.read(DATA_SIZE);
qDebug() << "emitting dataRead()";
emit dataRead(qa);
}
但无论如何,主要问题不在于多线程。问题是 QTextEdit::insertPlainText
操作并不便宜,尤其是当您有大量数据时。 FileReader
非常快速地读取文件数据,然后用要显示的新数据部分淹没您的小部件。
必须注意的是,您有一个非常无效的 HexViewer::loadData
实现。您逐个字符地插入文本数据,这使得 QTextEdit
不断重绘其内容并卡住 GUI。
您应该首先准备生成的十六进制字符串(注意数据参数不再是指针):
void HexViewer::loadData(QByteArray data)
{
QString tmp = data.toHex();
QString hexString;
hexString.reserve(tmp.size() * 1.5);
const int hexLen = 2;
for (int i = 0; i < tmp.size(); i += hexLen)
{
hexString.append(tmp.mid(i, hexLen) + " ");
}
_ui->hexTextView->insertPlainText(hexString);
}
无论如何,您的应用程序的瓶颈不是文件读取而是 QTextEdit
更新。按 block 加载数据,然后使用 QTextEdit::insertPlainText
将其附加到小部件不会加快任何速度。对于小于 1Mb 的文件,一次读取整个文件然后一步将生成的文本设置到小部件会更快。
我想您不能使用默认的 Qt 小部件轻松显示大于几兆字节的大文本。此任务需要一些重要的方法,通常与多线程或异步数据加载无关。这一切都是关于创建一些不会尝试立即显示其大量内容的棘手小部件。
关于c++ - 如何从 Qt 中的大文件异步加载数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34572043/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!