Obtener un istream de un char*


Tengo un char* y la longitud de datos que estoy recibiendo de una biblioteca, y necesito pasar los datos a una función que toma un istream.

Sé que puedo crear un stringstream pero eso copiará todos los datos. Y también, los datos seguramente tendrán 0s ya que es un archivo zip, y la creación de un stringstream tomará los datos hasta el primer 0 creo.

¿Hay alguna forma de crear un istream a partir de un char* y su tamaño sin copiar todos los datos?

 41
Author: marco.m, 2011-10-16

6 answers

Aquí hay un método no obsoleto encontrado en la web , tiene que derivar su propia clase std::streambuf, pero fácil y parece funcionar:

#include <iostream>
#include <istream>
#include <streambuf>
#include <string>

struct membuf : std::streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

int main()
{
    char buffer[] = "I'm a buffer with embedded nulls\0and line\n feeds";

    membuf sbuf(buffer, buffer + sizeof(buffer));
    std::istream in(&sbuf);
    std::string line;
    while (std::getline(in, line)) {
        std::cout << "line: " << line << "\n";
    }
    return 0;
}

Que produce:

line: I'm a buffer with embedded nullsand line
line:  feeds
 57
Author: HostileFork,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-16 02:47:53

Una solución no obsoleta usando Boost:

#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
using namespace boost::iostreams;

basic_array_source<char> input_source(my_ptr_to_char, byte_count);
stream<basic_array_source<char> > input_stream(input_source);

O aún más simple:

#include <boost/interprocess/streams/bufferstream.hpp>
using namespace boost::interprocess;

bufferstream input_stream(my_ptr_to_char, byte_count);
 11
Author: ZunTzu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-09 08:23:26

Necesitaba una solución que soportara tellg y seekg y no requería boost.

char_array_buffer from A beginner's guide to writing a custom stream buffer (std::streambuf) dio un punto de partida got.

Byte_array_buffer.h:

#include <cstdio>
#include <string>
#include <list>
#include <fstream>
#include <iostream>

//
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
//

class byte_array_buffer : public std::streambuf
{
public:
    byte_array_buffer(const uint8_t *begin, const size_t size);

private:
    int_type underflow();
    int_type uflow();
    int_type pbackfail(int_type ch);
    std::streamsize showmanyc();
    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 seekpos ( std::streampos sp,
                            std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);

    // copy ctor and assignment not implemented;
    // copying not allowed
    byte_array_buffer(const byte_array_buffer &);
    byte_array_buffer &operator= (const byte_array_buffer &);

private:
    const uint8_t * const begin_;
    const uint8_t * const end_;
    const uint8_t * current_;
};

Byte_array_buffer.cpp:

#include "byte_array_buffer.h"

#include <cassert>


byte_array_buffer::byte_array_buffer(const uint8_t *begin, const size_t size) :
begin_(begin),
end_(begin + size),
current_(begin_)
{
    assert(std::less_equal<const uint8_t *>()(begin_, end_));
}

byte_array_buffer::int_type byte_array_buffer::underflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_);
}

byte_array_buffer::int_type byte_array_buffer::uflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_++);
}

byte_array_buffer::int_type byte_array_buffer::pbackfail(int_type ch)
{
    if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1]))
        return traits_type::eof();

    return traits_type::to_int_type(*--current_);
}

std::streamsize byte_array_buffer::showmanyc()
{
    assert(std::less_equal<const uint8_t *>()(current_, end_));
    return end_ - current_;
}


std::streampos byte_array_buffer::seekoff ( std::streamoff off, std::ios_base::seekdir way,
                                           std::ios_base::openmode which )
{
    if (way == std::ios_base::beg)
    {
        current_ = begin_ + off;
    }
    else if (way == std::ios_base::cur)
    {
        current_ += off;
    }
    else if (way == std::ios_base::end)
    {
        current_ = end_;
    }

    if (current_ < begin_ || current_ > end_)
        return -1;


    return current_ - begin_;
}

std::streampos byte_array_buffer::seekpos ( std::streampos sp,
                                           std::ios_base::openmode which )
{
    current_ = begin_ + sp;

    if (current_ < begin_ || current_ > end_)
        return -1;

    return current_ - begin_;
}
 6
Author: catlan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 22:13:16

La única manera (simple) portátil incluye hacer la copia:

std::istringstream ss(std::string(buf,len));

De hecho, es probable que copie los datos dos veces, una para crear el string y otra para crear el istringstream. (Tal vez C++11 puede evitar una de las copias a través de un constructor de movimiento; no estoy seguro.)

Sin embargo, si tiene suerte, su implementación de C++ le permitirá hacer esto:

std::istringstream ss;
ss.rdbuf()->pubsetbuf(buf,len);

Bajo GNU C++ (y, creo, algunas otras implementaciones), esto creará el stringstream sin copiar los datos. Pero esto es un comportamiento "definido por la implementación" de acuerdo con la especificación. (Véase también esta pregunta.)

Al incluir el parámetro len, se asegura de que ambos no tendrán ningún problema con los caracteres null.

La única forma portable de hacer lo que quieres es implementar tu propia subclase de stringbuf y usarla para inicializar el stringstream. No para los débiles de corazón.

 4
Author: Nemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:19

¿Has probado std:: istream? http://stdcxx.apache.org/doc/stdlibref/istrstream.html

Técnicamente, creo que está en desuso, pero sigue siendo parte del estándar.

 1
Author: jeffrey_t_b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-16 02:45:43

Prueba el Impulso.Iostreams array source y sink classes.

Http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/index.html

 -1
Author: Benjamin Lindley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-16 02:55:45