2010-11-03 12 views
6

Questo è quello che ho provato finora, ma senza successo:Lettura di un flusso di file parziale in una stringa utilizzando iteratori

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); 
} 

so come leggere l'intero file.

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

Ma questo non è quello che voglio fare. Sto ottenendo una stringa vuota. Se guardo prima e ultimo in un debugger, indicano la stessa cosa anche dopo lo std :: advance.

+0

Qual è il risultato effettivo che si stai vedendo? Inoltre, per favore pubblica il codice * reale * che hai usato. Il codice sopra non viene nemmeno compilato (EDIT: prima che Charles lo risolvesse ...). –

+0

Ok corretto l'errore di compilazione. Spiace che è stato il mio male. Stavo digitando fuori di testa. –

+0

Non c'è bisogno di usare HTML, markdown funziona alla grande. –

risposta

5

C'è qualche ragione particolare per cui vuoi usare gli iteratori? Si può solo leggere i byte in una volta sola:

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

Se davvero si vuole leggere utilizzando iteratori, si potrebbe fare questo:

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, non è necessario. Ma vorrei sapere se è possibile. Grazie per la risposta –

+2

'file.read (& s [0], dimensione)' non è portabile e non è sicuro. basic_string non ha garanzia di archiviazione continua contigua. –

+0

@Steve: per quale implementazione è vero? –

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

istreambuf_iterators sono iteratori di input. Una volta che avanza per ultimo, viene modificato anche l'altro iteratore . Li stai trattando come Forward Iterators, che hanno la proprietà che puoi copiare un iteratore, avanzarlo, quindi ottenere una sequenza identica facendo avanzare la copia.

Per il caso generale:

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; 
} 

Tuttavia, in questo caso, si sarebbe meglio ridimensionare la stringa, utilizzando IStream :: leggere direttamente nel & risultato [0], e, infine, il controllo di leggere il numero desiderato di caratteri.

+0

Ma c'è un modo per fare qualcosa di simile usando gli iteratori, o del resto per ottenere un iteratore forward da un ifstream? –

+0

@Allen_SM: Certo, puoi usare gli iteratori, ho già incluso copy_n. Potresti scrivere un tipo iteratore per istream che è un Forward Iterator (poiché gli stream hanno un metodo seekg), ma non ce n'è bisogno. –

1

Non v'è alcun algoritmo standard che può aiutare a qui, ma è possibile utilizzare questo:

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

Questo può essere utilizzato con ReadPartial come questo:

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; 
} 
Problemi correlati