【问题标题】:QDataStream on external memory?外部存储器上的 QDataStream?
【发布时间】:2012-04-20 13:13:13
【问题描述】:

我想将 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;
    }
    

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    也许 fromRawData 有效:

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

    像这样使用它:

    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 序列化的任何其他数据。

    【讨论】:

    • 这是我最初的想法。但不幸的是QByteArray 在首次修改此类创建的实例时执行深度复制。正如他们所说的here这确保了原始数据数组本身永远不会被 QByteArray 修改。
    【解决方案2】:

    我认为你可能需要实现一个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)
    };
    

    【讨论】:

    • 将您的解决方案添加到原始消息中。
    【解决方案3】:

    为什么不使用QBuffer

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

    【讨论】:

    • 因为目标缓冲区 (char* out) 不受我控制,由外部库分配。问题的本质是如何在不使用中间缓冲区的情况下将这个外部内存包装到 QDataStream 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2014-09-14
    • 2012-02-07
    • 1970-01-01
    相关资源
    最近更新 更多