我有一个动态填充的文本区域(具体我在Qt中有一个QPlainTextEdit ,但它对于算法建议并不重要。)
现在问题有时会出现大量数据,因为我的应用程序中的数据越来越多,因为所有文本数据都在主内存中。
所以我想到了以下内容。我们可以使用一个文件来存储所有文本数据并动态显示有限数量的数据,但同时我必须通过创建在新行时触发的滚动事件来让用户觉得数据大小是文件的大小。来了。
这种问题是否有任何标准算法?
答案 0 :(得分:1)
子类QAbstractListModel
在那里实现缓存。
读取单元格值时,您将从缓存中获取数据,并在缓存中不存在值时更新它。
调整QTableView
,通过改变委托来实现细胞所需的可视化。请注意,您必须使用QTableView
,因为其他QAbstractItemView
已经破坏了项目,并且它们不能很好地处理非常大的模型(QTableView
没有这样的问题)。
有一段时间自我我写了大文件的十六进制查看器并测试了文件大小为2GB并且它工作得很好。
好的,我找到了我的旧代码,这可能就是一个很好的例子:
#include <QAbstractTableModel>
class LargeFileCache;
class LageFileDataModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit LageFileDataModel(QObject *parent);
// QAbstractTableModel
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
signals:
public slots:
void setFileName(const QString &fileName);
private:
LargeFileCache *cachedData;
};
// ----- cpp file -----
#include "lagefiledatamodel.h"
#include "largefilecache.h"
#include <QSize>
static const int kBytesPerRow = 16;
LageFileDataModel::LageFileDataModel(QObject *parent)
: QAbstractTableModel(parent)
{
cachedData = new LargeFileCache(this);
}
int LageFileDataModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return (cachedData->FileSize() + kBytesPerRow - 1)/kBytesPerRow;
}
int LageFileDataModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return kBytesPerRow;
}
QVariant LageFileDataModel::data(const QModelIndex &index, int role) const
{
if (index.parent().isValid())
return QVariant();
if (index.isValid()) {
if (role == Qt::DisplayRole) {
qint64 pos = index.row()*kBytesPerRow + index.column();
if (pos>=cachedData->FileSize())
return QString();
return QString("%1").arg((unsigned char)cachedData->geByte(pos), 2, 0x10, QChar('0'));
} else if (role == Qt::SizeHintRole) {
return QSize(30, 30);
}
}
return QVariant();
}
void LageFileDataModel::setFileName(const QString &fileName)
{
beginResetModel();
cachedData->SetFileName(fileName);
endResetModel();
}
这是一个缓存实现:
class LargeFileCache : public QObject
{
Q_OBJECT
public:
explicit LargeFileCache(QObject *parent = 0);
char geByte(qint64 pos);
qint64 FileSize() const;
signals:
public slots:
void SetFileName(const QString& filename);
private:
static const int kPageSize;
struct Page {
qint64 offset;
QByteArray data;
};
private:
int maxPageCount;
qint64 fileSize;
QFile file;
QQueue<Page> pages;
};
// ----- cpp file -----
#include "largefilecache.h"
const int LargeFileCache::kPageSize = 1024*4;
LargeFileCache::LargeFileCache(QObject *parent)
: QObject(parent)
, maxPageCount(1024)
, fileSize(0)
{
}
char LargeFileCache::geByte(qint64 pos)
{
// largefilecache
if (pos>=fileSize)
return 0;
for (int i=0, n=pages.size(); i<n; ++i) {
int k = pos - pages.at(i).offset;
if (k>=0 && k< pages.at(i).data.size()) {
pages.enqueue(pages.takeAt(i));
return pages.back().data.at(k);
}
}
Page newPage;
newPage.offset = (pos/kPageSize)*kPageSize;
file.seek(newPage.offset);
newPage.data = file.read(kPageSize);
pages.push_front(newPage);
while (pages.count()>maxPageCount)
pages.dequeue();
return newPage.data.at(pos - newPage.offset);
}
qint64 LargeFileCache::FileSize() const
{
return fileSize;
}
void LargeFileCache::SetFileName(const QString &filename)
{
file.close();
pages.clear();
file.setFileName(filename);
file.open(QFile::ReadOnly);
fileSize = file.size();
}
我在处理行数据时手动编写了缓存,但您可以使用QCache来帮助您执行缓存逻辑。
答案 1 :(得分:0)
使用mmap仅解决了如何在内存中只读取文件时如何读取文件。它没有解决编辑控件一次只有片段的问题。
我必须认为任何这样的系统都非常特定于所涉及的文本编辑小部件。在这种情况下,您可能需要弄清楚如何使用所需的功能扩展QPlainTextEdit
,或者创建一个新的文本编辑小部件(可能分支现有的小部件)。有许多文本编辑小部件可用作开源,可用作起点。
到目前为止,我一直在假设您要编辑此大文件中的文本。如果您只使用QPlainTextEdit
作为只读查看器,那么编写自己的只是一个大型文本流阅读小部件可能比扩展现有编辑器小部件容易得多。
答案 2 :(得分:0)
这是我的两分钱,
当我搜索类似的问题时,我从Fast textfile reading in c++
找到答案简而言之,内存映射了boost Lib中的文件。可能不仅对性能有帮助,而且对处理大量数据也有帮助。
链接中的示例,我可以检查行数并从Lib获取数据。
祝你好运