2010-09-30 38 views
6

Si quiero copiar el contenido de un archivo a un vector, que lo puede hacer como que:¿Cómo copiar una cierta cantidad de caracteres de un archivo a un vector STL-way?

std::ifstream file("path_to_file"); 
std::vector<char> buffer(std::istream_iterator<char>(file), 
         std::istream_iterator<char>()); 

Mi pregunta es, ¿cómo iba a hacerlo si quiero copiar sólo los primeros n caracteres?

Editar Podría escribir mi propia versión de copy, pero ¿hay alguna manera de hacerlo con solo componentes existentes?

+0

No es bonito pero podría usar replace_copy_if, use el predicado para verificar si ha copiado n chars !! – DumbCoder

Respuesta

6

Como se observó en Steve, esto necesitaría copy_n(), que, debido a un descuido, no está en la biblioteca estándar actual, pero estará en C++ 1x. Se puede implementar fácilmente uno mismo, aquí hay uno que creo que es correcto:

template<class InIt, class OutIt> 
OutIt copy_n(InIt src, OutIt dest, size_t n) 
{ 
    if (!n) return dest; 
    *dest = *src; 
    while (--n) 
    *++dest = *++src; 
    return ++dest; 
} 

Tenga en cuenta que std::copy_n() presume el iterador de entrada a ser capaz de entregar n objetos. Al leer de un archivo, esto podría ser problemático.


Ausente de std::copy_n(), podría utilizar std::generate_n.

template< typename InIt > 
struct input_generator { 
    typedef std::iterator_traits<InIt>::value_type value_type; 

    input_generator(InIt begin, InIt end) begin_(begin), end_(end) {} 

    value_type operator()() 
    { 
    assert(it_ != end); 
    return *it_++; 
    } 

    Init begin_; 
    Init end_; 
}; 


std::vector<char> buffer; 
buffer.reserve(42); 

std::generate_n(std::back_inserter(buffer) 
       , 42 
       , input_generator(std::istream_iterator<char>(file)) 
       , input_generator(std::istream_iterator<char>())); 

Sin embargo, no veo esto como una ventaja sobre la lectura directamente desde el archivo como avakar showed.

+0

La implementación de Sbi no fue correcta para los iteradores de flujo, que leen de la secuencia en incrementos e inicializaciones. Lo arreglé. –

+0

@Don: Gracias. Esa es la razón por la que incluso tales algoritmos simples deberían estar en el laboratorio estándar: es fácil dejar que errores sutiles se deslicen incluso en los más simples. – sbi

0
char *buffer = new char[n]; 
file.read(buffer,n); 
std::vector<char> myVector 
for (int i=0;i<n;i++) myVector.push_back(buffer[i]); 
delete [] buffer; 

// myVector now holds the first n bytes of file. 

Puede que no sea la forma más bonita ni la más rápida, pero así es cómo lo haría.

+0

Una versión más corta sería '' std :: vector myVector (buffer, n); ' – Default

+3

que debería ser' std :: vector myVector (buffer, buffer + n); '(y omitir el forloop) – Default

+1

¿Qué hay de malo en leer directamente en un vector (suficientemente redimensionado)? – sbi

1

El "modo STL" es usar copy_n, que está en el estándar STL pero no en el estándar C++.

+0

Suena razonable, pero no recomendable si la portabilidad es una preocupación. Además, ¿se agrega esto al estándar en C++ x0? –

+0

Sí, está en C++ 0x. Si la portabilidad es una preocupación, entonces no haga las cosas de la manera STL, hágalo de la manera estándar de C++ ;-) En este caso, eso probablemente signifique implementar copy_n usted mismo, en su propio espacio de nombres, tal vez tomando una implementación desde otro lugar. –

8

Como Alexander señala, la forma más rápida sería

std::vector<char> buffer(n); 
file.read(&buffer[0], n); 

En C++ 0x, se puede utilizar en lugar de buffer.data()&buffer[0]; este último tiene un comportamiento indefinido si n == 0.

0

Crédito debido a @sbi, me olvidé de generate_n.

El streambuf dentro file tiene una función snextc que devuelve el siguiente carácter, calificándolo como una función de generador, una vez que su this argumento implícito está obligado.

generate_n(back_inserter(buffer), 42, 
      tr1::bind(tr1::mem_fn(&streambuf::snextc), file.rdbuf())); 

Para vector, solo lea directamente. Esto es bueno para deque o lo que sea.

Cuestiones relacionadas