5

ifstream一緒に集約された多数のサブファイルを含む大きなファイルを表すがあるとします。他のコードがそのサブストリームから独立istreamした.ifstreamistream

これを達成する方法についてのアイデアはありますか?

編集 - ブーストは避けたいと思います。

4

4 に答える 4

6

これは、指定された位置から開始して指定されたサイズまで読み取る、含まれている streambuf から読み取る streambuf "フィルター" の例です。を作成し、元の をsubstreambuf渡してアクセスを変換し、基になる の目的の場所からすべてが読み取られるようにします。streambufsubstreambufstreambuf

sgetcsnextcfromの呼び出しに伴うオーバーヘッドのほとんどは、最適化して取り除く必要がunderflowあります。uflow多くの抽出演算子はバイトごとに機能するため、サブセクション内の読み取り位置を維持し、サブセクションの終わりを確認する以外に追加のオーバーヘッドが発生することはありません。もちろん、このクラスでは大量のデータを読み取ると効率が低下します (ただし、これは修正される可能性があります)。

これには、要求された場所が基になる 内にあることをテストするなどの改善が必要streambufです。

class substreambuf : public std::streambuf
{
public:

    substreambuf(std::streambuf *sbuf, std::size_t start, std::size_t len) : m_sbuf(sbuf), m_start(start), m_len(len), m_pos(0)
    {
        std::streampos p = m_sbuf->pubseekpos(start);
        assert(p != std::streampos(-1));
        setbuf(NULL, 0);
    }

protected:

    int underflow()
    {
        if (m_pos + std::streamsize(1) >= m_len)
            return traits_type::eof();
        return m_sbuf->sgetc();
    }

    int uflow()
    {
        if (m_pos + std::streamsize(1) > m_len)
            return traits_type::eof();
        m_pos += std::streamsize(1);
        return m_sbuf->sbumpc();
    }

    std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
    {
        std::streampos cursor;

        if (way == std::ios_base::beg)
            cursor = off;
        else if (way == std::ios_base::cur)
            cursor = m_pos + off;
        else if (way == std::ios_base::end)
            cursor = m_len - off;

        if (cursor < 0 || cursor >= m_len)
            return std::streampos(-1);
        m_pos = cursor;
        if (m_sbuf->pubseekpos(m_start + m_pos, std::ios_base::beg) == std::streampos(-1))
            return std::streampos(-1);

        return m_pos;
    }

    std::streampos seekpos(std::streampos sp, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
    {
        if (sp < 0 || sp >= m_len)
            return std::streampos(-1);
        m_pos = sp;
        if (m_sbuf->pubseekpos(m_start + m_pos, std::ios_base::beg) == std::streampos(-1))
            return std::streampos(-1);
        return m_pos;
    }

private:
    std::streambuf *m_sbuf;
    std::streampos m_start;
    std::streamsize m_len;
    std::streampos m_pos;
};

こんな感じで使えます

using namespace std;

void somefunc(ifstream &bigifs)
{
    substreambuf sbuf(bigifs.rdbuf(),100,100);
    //new istream with the substreambuf as its streambuf
    istream isub(&sbuf);

    //use isub normally
}

これは、Streambufs のフィルタリングに触発されました。

于 2011-10-05T06:15:41.703 に答える
1

すべての iostream は、カスタム ロジックのほとんどをstreambuf特殊化に配置します。fstream(またはbasic_fstream)istreamのインスタンスで初期化しますfile_bufstringstream( )も同様stringbuf。独自のサブストリーム ストリームを展開したい場合streambufは、親ストリームに関して独自に実装することで実行できます。

于 2011-10-04T04:23:23.490 に答える
1

Boost.Iostreamsライブラリを使用して、このようなことを行いました。チュートリアル|ライティングデバイスの下を見てください。アイデアは、低レベル インターフェイス (読み取り/書き込み/シーク) を実装する "デバイス" クラスを作成し、デバイス クラスを使用して istream/ostream 派生クラスをインスタンス化して、実際の I/O を実行することです。

于 2011-10-01T22:25:05.603 に答える
0

ちょっとしたアイデア: コードのクライアント側 (つまり、入力ストリームを使用する部分) を制御できる場合は、以下に示すように、2 つの追加パラメーターを受け入れるようにコードを変更することをお勧めします。

// Old code
void ClassUsingInput::SetInput(std::streambuf & inputbuf)
{
   // Implementation ...
}

になることができる :

// New code
void ClassUsingInput::SetInput(std::streambuf & inputbuf, std::streampos position, std::streamsize size) 
{
    inputbuf.pubseekpos(position) ;
    // internally use size to detect end-of-substream
}
于 2011-10-04T05:42:57.170 に答える