2010-11-03 4 views
6

Esto es lo que he tratado hasta ahora, pero sin éxito:Lectura de una corriente parcial de archivos en una cadena utilizando iteradores

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last(_file); 
    std::advance(last, _size); 
    return std::string(first, last); 
} 

que saben leer todo el archivo.

std::string Read(std::ifstream& _file) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last(); 
    return std::string(first, last); 
} 

Pero esto no es lo que quiero hacer. Estoy recibiendo una cadena vacía. Si miro primero y último en un depurador, apuntan a lo mismo incluso después del estándar :: avance.

+0

Cuál es el resultado real que se ¿Estás viendo? Además, publique el código * real * que utilizó. El código anterior ni siquiera se compila (EDIT: antes de que Charles lo arregló ...). –

+0

Ok corrigió el error de compilación. Lo siento, fue mi mal. Estaba tipeando de mi cabeza. –

+0

No es necesario usar HTML, el descuento funciona muy bien. –

Respuesta

5

¿Hay alguna razón en particular por la que desee utilizar iteradores? Se podía leer los bytes de una sola vez:

std::string s(_size, '\0'); 
_file.read(&s[0], _size); 

Si realmente desea leer usando iteradores, usted puede hacer esto:

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last; 
    std::string s; 
    s.reserve(_size); 
    while (_size-- && first != last) s += *first++; 
    return s; 
} 
+0

No, no es necesario. Pero me gustaría saber si es posible. Gracias por la respuesta –

+2

'file.read (& s [0], size)' no es portátil ni inseguro. basic_string no tiene la garantía de almacenamiento contiguo del vector. –

+0

@Steve: ¿para qué implementación es así de cierto? –

5
std::istreambuf_iterator<char> first(_file); 
std::istreambuf_iterator<char> last(_file); 
std::advance(last, _size); 

istreambuf_iterators son iteradores de entrada. Una vez que avanzas por última vez, el otro iterador también se modifica. Los está tratando como Iteradores directos, que tienen la propiedad de que puede copiar un iterador, avanzarlo y obtener una secuencia idéntica avanzando la copia.

Para el caso general:

template<class InIter, class Size, class OutIter> 
void copy_n(InIter begin, InIter end, Size n, OutIter dest) { 
    for (; begin != end && n > 0; ++begin, --n) { 
    *dest++ = *begin; 
    } 
} 

//... 
std::string ReadPartial(std::istream& file, int size) { 
    std::string result; 
    copy_n(istreambuf_iterator<char>(file), istreambuf_iterator<char>(), 
     size, back_inserter(result)); 
    return result; 
} 

Sin embargo, en este caso, sería mejor cambiar el tamaño de la cadena, usando istream :: leer directamente en & resultado [0], y finalmente comprobar que lea el número deseado de caracteres.

+0

¿Pero hay una manera de hacer algo similar usando iteradores, o para ese asunto obtener un iterador directo de un ifstream? –

+0

@Allen_SM: Claro que puedes usar iteradores, ya incluí copy_n. Podría escribir un tipo de iterador para istreams, que es un iterador directo (ya que istream tiene un método seekg), pero no es necesario. –

1

No existe un algoritmo estándar que puede ayudar aquí, pero se puede usar éste:

template< class InputIterator, class OutputIterator> 
OutputIterator copy_n(InputIterator from, 
         size_t n, 
         OutputIterator to) 
{ 
    while (n) 
    { 
     *to = *from; 
     ++from; 
     ++to; 
     --n; 
    } 
    return to; 
} 

Esto puede ser usado con ReadPartial así:

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::string result; 

    copy_n(first, _size, std::back_inserter(result)); 
    return result; 
} 
Cuestiones relacionadas