簡體   English   中英

std :: stringstream具有二進制數據的流運算符

[英]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,則可以輕松編寫自己的beginend 。)

這樣,您將確切地知道字節是什么,而不必依賴於實現表示任何特定類型的方式。

或者:如果您正在讀寫二進制數據,則可能需要使用>><<來定義執行該操作的類。 這樣的類與std::istreamstd::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_tuint32_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM