2014-04-28 2 views
2

Я работаю над написанием некоторых тестовых примеров для класса, который предположительно читается с std::istream и записывается в std::ostream. В рамках процесса тестирования я хотел бы вручную создать блок данных тестового файла, обернуть его в std::stringstream и передать его в мой класс для обработки.std :: stringstream операторы потока с двоичными данными

Я чувствую, что мое текущее решение не хватает, несмотря на то, что оно делает работы. Мне действительно не нравится использовать эти необработанные вызовы записи с reinterpret_cast.

std::stringstream file; 

uint32_t version = 1; 
uint32_t dataSize = 10; 
uint32_t recordCount = 3; 

file.write(reinterpret_cast<char*>(&version), sizeof(version)); 
file.write(reinterpret_cast<char*>(&dataSize), sizeof(dataSize)); 
file.write(reinterpret_cast<char*>(&recordCount), sizeof(recordCount)); 

myclass.read(file) 

Есть ли способ, которым я могу использовать операторы потока для записи этих данных в двоичной форме? Я надеюсь на что-то более похожее на следующее.

std::stringstream file; 

uint32_t version = 1; 
uint32_t dataSize = 0; 
uint32_t recordCount = 3; 

file << version << dataSize << recordCount; 

myclass.read(file); 

Если я иду по этому пути, извлекая результаты в числовом 103, который, как ожидается, в контексте ASCii, но я, очевидно, пытаясь избежать сериализаций моих данных в этой манере.

+0

HTTP:.//stackoverflow.com/questions/1150843/binary-version-of- iostream – oakad

+1

iostream не разработан с учетом этого использования. Возможно, вы захотите рассмотреть другие библиотеки, такие как boost :: spirit :: karma или boost :: serialize. – oakad

+0

@oakad Или если вы хотите использовать форматы '>>' и '<<' (скажем, потому что вы не сериализуете, а читаете произвольные данные в двоичном формате), довольно просто определить новые классы потоков, контракт "- это своего рода двоичный формат, а не текст. –

ответ

2

Существует проблема с кодом: при использовании reinterpret_cast, вы на самом деле не знаю, что вы пишете в поток, так что вы не знаете, что вы тестируете. Если вы хотите проверить, как ваш код реагирует на поток байтов в двоичный формат, вы можете легко инициализировать std::istringstream с произвольным потоком байтов:

char bytes[] = { /*...*/ }; 
std::istringstream(std::string(std::begin(bytes), std::end(bytes))); 

(Если вы не имеете C++ 11, вы можете легко написать свой собственный begin и end.)

Таким образом, вы будете точно знать, что байты, а не в зависимости от Aleas того, как ваша реализация представляет собой какой-либо конкретный тип ,

Альтернативно: если вы читаете и записываете двоичные данные, вы можете определить классы, которые это делают, используя >> и <<. Таких классы были бы связаны с std::istream и std::ostream, но могут логически использовать std::ios_base для обеспечивает поддержку традиционных сообщений об ошибках и интерфейс к std::streambuf .Класс будет тогда иметь члены что-то вроде следующего:

namespace { 

class ByteGetter 
{ 
public: 
    explicit   ByteGetter(ixdrstream& stream) 
     : mySentry(stream) 
     , myStream(stream) 
     , mySB(stream->rdbuf()) 
     , myIsFirst(true) 
    { 
     if (! mySentry) { 
      mySB = NULL ; 
     } 
    } 
    std::uint8_t  get() 
    { 
     int     result = 0 ; 
     if (mySB != NULL) { 
      result = mySB->sgetc() ; 
      if (result == EOF) { 
       result = 0 ; 
       myStream.setstate(myIsFirst 
        ? std::ios::failbit | std::ios::eofbit 
        : std::ios::failbit | std::ios::eofbit | std::ios::badbit) ; 
      } 
     } 
     myIsFirst = false ; 
     return result ; 
    } 

private: 
    ixdrstream::sentry mySentry ; 
    ixdrstream&   myStream ; 
    std::streambuf*  mySB ; 
    bool    myIsFirst ; 
} ; 
} 

ixdrstream& 
ixdrstream::operator>>(std::uint32_t&  dest) 
{ 
    ByteGetter   source(*this) ; 
    std::uint32_t  tmp = source.get() << 24 ; 
    tmp |= source.get() << 16 ; 
    tmp |= source.get() << 8 ; 
    tmp |= source.get()  ; 
    if (*this) { 
     dest = tmp ; 
    } 
    return *this ; 
} 

(Для максимальной переносимости, вы можете обыкновение избежать uint8_t и uint32_t На этом уровне, писать код без зная точный размер. тип является немного более сложным, так что если вы уверены, что вы никогда не будете иметь в порт для экзотического системы, в которой они не могут быть определены, это, вероятно, стоит экономить себе дополнительную работу)

+0

Я ценю ответ. Я надеялся удовлетворить свои потребности без какой-либо сложности, но пока сложность изолирована и интерфейс чист, он соответствует моей общей цели. В конце концов, я решил использовать платформу сериализации boost для разработки моего собственного интерфейса. – vmrob

1

Вы можете объявить оператор << для ostreams (так что не только потоки строк, но и потоки файлов). Что-то вроде следующего может работать (непроверенные), но вы можете столкнуться с проблемами с типом (uint32_t):

std::ostream& operator<<(std::ostream& stream, uint32_t value) 
{ 
    stream.write(reinterpret_cast<char*>(&value), sizeof(value)); 
    return stream; 
} 

std::stringstream file; 
file << version << dataSize << recordCount; 

EDIT:

Из значения типа имеет оператор << уже определены. Одним из вариантов было бы объявить новый оператор <=:

std::ostream& operator<=(std::ostream& stream, uint32_t value); 
file <= version <= dataSize <= recordCount; 

Оба оператора работать в левой направо моды, так что это может работать, может быть не самым хорошим решением, хотя.

+0

Как вы думали, тип действительно немного затрудняет использование этого решения. 'uint32_t' - это typedef для unsigned int в моей системе, и для этого типа существует перегрузка. Однако, если бы я хотел использовать пользовательский класс/тип, это будет работать очень хорошо. – vmrob

+0

@vmrob Возможно, вы можете перегрузить другого оператора? см. EDIT. – ilent2

+1

Я думаю, что сработает. Оценив мой код, я решил взглянуть на библиотеку boost :: serialize. Кажется, что вы делаете то, что вы предложили, перегрузив оператора ('' 'и специально) и имеет много других функций, которые, я думаю, будут хорошо работать для моей программы. – vmrob

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