[英]std::stringstream stream operators with binary data
我正在為類編寫一些測試用例,這些類可能會從std::istream
讀取並寫入std::ostream
。 作為測試過程的一部分,我想手動創建一個測試文件數據塊,將其包裝在std::stringstream
,然后將其傳遞給我的類進行處理。
我覺得我的當前解決方案缺乏,盡管它確實有效。 我真的不喜歡將那些原始的write調用與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上下文中是可以預期的,但是我顯然想避免以這種方式序列化我的數據。
您的代碼有一個問題:當您使用reinterpret_cast
,您實際上並不知道您要寫入流中的內容,因此您也不知道要測試什么。 如果要測試代碼對二進制格式的字節流的反應,可以使用任意字節流輕松地初始化std::istringstream
:
char bytes[] = { /*...*/ };
std::istringstream( std::string( std::begin( bytes ), std::end( bytes ) ) );
(如果沒有C ++ 11,則可以輕松編寫自己的begin
和end
。)
這樣,您將確切地知道字節是什么,而不必依賴於實現表示任何特定類型的方式。
或者:如果您正在讀寫二進制數據,則可能需要使用>>
和<<
來定義執行該操作的類。 這樣的類與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
。在此級別上,編寫代碼而不知道類型的確切大小會有些困難,因此,如果您確定不必將其移植到可能沒有定義它們的異國情調的系統,可能值得為自己節省額外的工作。)
您可以為ostream聲明一個運算符<<
(因此不僅是字符串流,而且還有文件流)。 可能會發生以下情況(未經測試),但可能會遇到類型(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;
編輯:
由於具有類型值,因此已經定義了<<
操作符。 一種替代方法是聲明一個新的運算符<=
:
std::ostream& operator<=(std::ostream& stream, uint32_t value);
file <= version <= dataSize <= recordCount;
兩家運營商都以從左到右的方式進行操作,因此這可能會起作用,盡管可能不是最好的解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.