2012-04-07 2 views
0

Я хотел бы сериализовать QVector в char * array. Я делаю это с помощью следующего кода:QDataStream во внешней памяти?

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

Я гарантирую, что out достаточно велик. Из-за того, что этот код называется очень часто, я бы хотел избежать этой ненужной операции std::copy и сделать либо QByteArray, либо QDataStream работы над предопределенной пользовательской памятью, на которую указывает out. Это возможно? Какие-нибудь идеи?

UPDATE: QByteArray :: fromRawData() не соответствует потребностям потому что это не позволяет изменить символ * буфер был создан, и другими словами, 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; 
    } 
    

ответ

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) 
}; 
+0

Он работает как шарм, спасибо! – prokher

+0

Добавлено ваше решение в исходное сообщение. – prokher

0

Может быть fromRawData работы:

QByteArray QByteArray :: fromRawData (Const символ * данные, 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.

+1

Это была моя первоначальная идея. Но, к сожалению, 'QByteArray' выполняет глубокую копию при первой модификации такого созданного экземпляра. Как говорится [здесь] (http://qt-project.org/doc/qt-4.8/qbytearray.html#fromRawData). _Это гарантирует, что сам массив необработанных данных никогда не будет изменен QByteArray._ – prokher

0

Почему бы не использовать QBuffer?

QByteArray myBuffer; 
myBuffer.reserve(10000); // no re-allocation 

QBuffer buffer(&myBuffer); 
buffer.open(QIODevice::WriteOnly); 

QDataStream out(&buffer); 
out << QApplication::palette(); 
+0

Поскольку целевой буфер ('char * out') вышел из моего контроля и выделен внешней библиотекой. Суть вопроса заключалась в том, как обернуть эту внешнюю память в QDataStream без использования промежуточных буферов. – prokher

Смежные вопросы