web-dev-qa-db-ja.com

データをコピーせずに(char *、size_t)からC ++メモリーストリームを作成する簡単な方法は?

私は既製のものを見つけることができなかったので、私は思いつきました:

class membuf : public basic_streambuf<char>
{
public:
  membuf(char* p, size_t n) {
    setg(p, p, p + n);
    setp(p, p + n);
  }
}

使用法:

char *mybuffer;
size_t length;
// ... allocate "mybuffer", put data into it, set "length"

membuf mb(mybuffer, length);
istream reader(&mb);
// use "reader"

stringstreamは知っていますが、指定された長さのバイナリデータを処理できないようです。

ここで自分のホイールを発明していますか?

[〜#〜]編集[〜#〜]

  • 必須ではない入力データをコピーし、データを反復処理するものを作成するだけです。
  • 移植可能でなければなりません-少なくとも、gccとMSVCの両方で動作するはずです。
30

入力データが(テキストではなく)バイナリであり、そこからバイナリデータのチャンクを抽出するとします。入力データのコピーを作成せずにすべて。

boost::iostreams::basic_array_sourceboost::iostreams::stream_buffer(from Boost.Iostreams )をboost::archive::binary_iarchive(from Boost.Serialization )と組み合わせると、便利な抽出>>演算子を使用して、バイナリデータのチャンクを読み取ります。

#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/archive/binary_iarchive.hpp>

int main()
{
    uint16_t data[] = {1234, 5678};
    char* dataPtr = (char*)&data;

    typedef boost::iostreams::basic_array_source<char> Device;
    boost::iostreams::stream_buffer<Device> buffer(dataPtr, sizeof(data));
    boost::archive::binary_iarchive archive(buffer, boost::archive::no_header);

    uint16_t Word1, Word2;
    archive >> Word1 >> Word2;
    std::cout << Word1 << "," << Word2 << std::endl;
    return 0;
}

AMD64のGCC 4.4.1では、次のように出力されます。

1234,5678

Boost.Serializationは非常に強力で、すべての基本的な型、文字列、さらにはSTLコンテナーをシリアル化する方法を知っています。型を簡単にシリアル化できます。ドキュメントを参照してください。 Boost.Serializationソースのどこかに隠されているのは、マシンのエンディアンの適切なスワッピングを実行する方法を知っているポータブルバイナリアーカイブの例です。これはあなたにも役立つかもしれません。

Boost.Serializationの空想を必要とせず、バイナリデータをfread()タイプの方法で読みたい場合は、basic_array_sourceをより簡単な方法で使用できます。

#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

int main()
{
    uint16_t data[] = {1234, 5678};
    char* dataPtr = (char*)&data;

    typedef boost::iostreams::basic_array_source<char> Device;
    boost::iostreams::stream<Device> stream(dataPtr, sizeof(data));

    uint16_t Word1, Word2;
    stream.read((char*)&Word1, sizeof(Word1));
    stream.read((char*)&Word2, sizeof(Word2));
    std::cout << Word1 << "," << Word2 << std::endl;

    return 0;
}

このプログラムでも同じ出力が得られます。

28
Emile Cormier

何が必要かわかりませんが、これで十分でしょうか?

char *mybuffer;
size_t length;
// allocate, fill, set length, as before

std::string data(mybuffer, length);
std::istringstream mb(data);
//use mb
5
crmoore

標準のストリームバッファにはこの機能があります。
ストリームを作成します。バッファを取得してオーバーライドします。

#include <sstream>
#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    // Your imaginary buffer
    char    buffer[]    = "A large buffer we don't want to copy but use in a stream";

    // An ordinary stream.
    std::stringstream   str;

    // Get the streams buffer object. Reset the actual buffer being used.
    str.rdbuf()->pubsetbuf(buffer,sizeof(buffer));

    std::copy(std::istreambuf_iterator<char>(str),
              std::istreambuf_iterator<char>(),
              std::ostream_iterator<char>(std::cout)
             );
}
4
Martin York

質問者はデータをコピーしない何かを望んでおり、彼の解決策はうまくいきます。私の貢献は少しクリーンアップすることなので、メモリ内のデータの入力ストリームである単一のオブジェクトを作成できます。私はこれをテストしましたが、うまくいきます。

class MemoryInputStream: public std::istream
    {
    public:
    MemoryInputStream(const uint8_t* aData,size_t aLength):
        std::istream(&m_buffer),
        m_buffer(aData,aLength)
        {
        rdbuf(&m_buffer); // reset the buffer after it has been properly constructed
        }

    private:
    class MemoryBuffer: public std::basic_streambuf<char>
        {
        public:
        MemoryBuffer(const uint8_t* aData,size_t aLength)
            {
            setg((char*)aData,(char*)aData,(char*)aData + aLength);
            }
        };

    MemoryBuffer m_buffer;
    };
2
Graham Asher