外部内存上的QDataStream

QDataStream on external memory?

本文关键字:QDataStream 内存 外部      更新时间:2023-10-16

我想将QVector序列化为char*数组。我通过以下代码做到这一点:

QVector<int> in;
...
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::WriteOnly);
stream << in;
std::copy(bytes.constData(), bytes.constData() + bytes.size(), out);

我保证out足够大。由于此代码被频繁调用,我希望避免这种不必要的std::copy操作,并使QByteArrayQDataStreamout指向的预分配用户内存上工作。这可能吗?有什么好主意吗?

UPDATEQByteArray::fromRawData()与需求不匹配,因为它不允许更改创建的char*缓冲区,换句话说,QByteArray在第一次修改创建的实例时执行深度复制。正如他们所说这确保了原始数据数组本身永远不会被QByteArray修改

解决方案:@skyhisi提出的解决方案完全符合我的需求。完整的代码如下。

  1. SimpleBuffer.hpp

    #pragma once
    #include <QtCore/QIODevice>
    class SimpleBuffer : public QIODevice {
      Q_OBJECT
      Q_DISABLE_COPY(SimpleBuffer)
    public:
      SimpleBuffer(char* const begin, const char* const end) :
        _begin(begin),
        _end(end){}
      virtual bool atEnd() const {
        return _end == _begin;
      }
      virtual bool isSequential() const {
        return true;
      }
    protected:
      virtual qint64 readData(char*, qint64) {
        return -1;
      }
      virtual qint64 writeData(const char* const data, const qint64 maxSize) {
        const qint64 space = _end - _begin;
        const qint64 toWrite = qMin(maxSize, space);
        memcpy(_begin, data, size_t(toWrite));
        _begin += toWrite;
        return toWrite;
      }
    private:
      char* _begin;
      const char* const _end;
    };
    
  2. main.cpp

    #include "SimpleBuffer.hpp"
    #include <QtCore/QVector>
    #include <QtCore/QDataStream>
    #include <QtCore/QByteArray>
    int main(int, char**) {
      QVector<int> src;
      src << 3 << 7 << 13 << 42 << 100500;
      const size_t dataSize = sizeof(quint32) + src.size() * sizeof(int);
      char* const data = new char[dataSize];
      // prepare stream and write out the src vector
      {
        SimpleBuffer simpleBuffer(data, data + dataSize);
        simpleBuffer.open(QIODevice::WriteOnly);
        QDataStream os(&simpleBuffer);
        os << src;
      }
      // read vector with QByteArray
      QVector<int> dst;
      {
        const QByteArray byteArray = QByteArray::fromRawData((char*)data, dataSize);
        QDataStream is(byteArray);
        is >> dst;
      }
      delete [] data;
      // check we've read exactly what we wrote
      Q_ASSERT(src == dst);
      return 0;
    }
    

我认为您可能需要实现QIODevice,您可以很容易地制作一个非常简单的顺序设备。这是我很快拼凑出来的一个,我还没有检查它是否有效(请随意让它发挥作用并编辑帖子)。

class SimpleBuffer : public QIODevice
{
    Q_OBJECT
    public:
        SimpleBuffer(char* begin, char* end):mBegin(begin),mEnd(end){}
        virtual bool atEnd() const {return mEnd == mBegin; }
        virtual bool isSequential() const { return true; }
    protected:
        virtual qint64 readData(char*, qint64) { return -1; }
        virtual qint64 writeData(const char* data, qint64 maxSize)
        {
            const qint64 space = mEnd - mBegin;
            const qint64 toWrite = qMin(maxSize, space);
            memcpy(mBegin, data, size_t(toWrite));
            mBegin += toWrite;
            return toWrite;
        }
   private:
        char* mBegin;
        char* mEnd;
        Q_DISABLE_COPY(SimpleBuffer)
};

也许来自RawData的作品:

QByteArray QByteArray::fromRawData(const char*data,int size)[static]

使用它类似于:

char* out=new char[enoughbytes]; // preallocate at suitable scope
QVector<int> in; 
QByteArray ba=QByteArray::fromRawData(out,enoughbytes); 
QDataStream stream(&ba,QIODevice::WriteOnly); 
stream << in;

请注意,QDataStream在数据的开头添加了一些自己的数据(虽然不多),所以记住要为此预分配更多的数据,以及QVector序列化的任何其他数据。

为什么不使用QBuffer?

QByteArray myBuffer;
myBuffer.reserve(10000); // no re-allocation
QBuffer buffer(&myBuffer);
buffer.open(QIODevice::WriteOnly);
QDataStream out(&buffer);
out << QApplication::palette();