2010-08-22 8 views
8

Come faccio a leggere esattamente 128 byte da un flusso in un oggetto stringa?Come posso leggere esattamente 128 byte da un flusso in un oggetto stringa?

Ho scritto un codice per leggere i primi 128 byte di un file e stamparlo e quindi gli ultimi 128 byte del file e stamparlo. L'ultima parte funziona, dal momento che si può facilmente iterare a EOF, ma come faccio a ottenere esattamente 128 byte dal fronte? Il codice sottostante non funziona poiché non è possibile aggiungere 128 a un iteratore ifstream, non è indicizzabile, solo incrementabile (sembra).

Certo, potrei fare un iteratore e * + + 128 volte, ma ci deve essere una linea semplice per farlo, giusto?

#include <iostream> 
#include <fstream> 
#include <string> 

int main(int argc, char **argv) 
{ 
    std::ifstream ifs ("input.txt",std::ifstream::in | std::ifstream::binary); 

    if (ifs.good()) 
    { 
    // read first 128 bytes into a string 
     ifs.seekg(0,std::ifstream::beg); 
     std::string first128((std::istreambuf_iterator<char>(ifs)), 
          (std::istreambuf_iterator<char>(ifs))+128); 

     std::cout << first128 << std::endl; 

    // read last 128 bytes into a string 
     ifs.seekg(-128,std::ifstream::end); 
     std::string last128((std::istreambuf_iterator<char>(ifs)), 
          std::istreambuf_iterator<char>()); 

     std::cout << last128 << std::endl; 

     return 0; 
    } 

    return 1; 
} 
+0

Che ne dici di istream :: readsome? – Chubsdad

+0

read/readsome funziona solo su char * s e non è possibile ottenere un char * (solo un const char *) da un tipo di stringa, quindi non è possibile leggere direttamente in un tipo di stringa. –

risposta

1
char buffer[129]; 
ifs.read (buffer,128); 
buffer[128] = '\0'; 
first128 = buffer; 

Che ne dite di questo allora:

template <typename Itr, typename Out> 
void copy_n(Itr it, size_t count, Out out) 
{ 
    for(size_t i=0;i<count;++i) 
     out = *it++; 
} 

... 

std::string first128; 
std::istreambuf_iterator<char> it(ifs); 
copy_n(it, 128, 
    std::back_inserter<std::string>(first128)); 
+0

byte waster! buffer di caratteri [128]; ifs.read (buffer, 128); std :: string first128 (buffer, 128); Ma in realtà voglio farlo nel modo più puro possibile. Le risposte senza parentesi angolari non devono essere applicate! –

+0

@ Hospitality sud: ho modificato per includere un'altra versione. – ngoozeff

+0

Penso che la prima risposta sia perfetta. Vuoi entrare in una stringa, basta creare una stringa std :: string di 128 e passarla come il buffer da leggere. Pensare che non sia puro sta affermando che la libreria standard è in qualche modo impura. –

0

La mia risposta utilizza un buffer intermedio, ma forse saranno felici che utilizza iteratori per inizializzare la stringa dal buffer.

std::vector<char> buffer(128); // create a buffer 
ifs.read(&buffer[0], buffer.size()); // read to buffer 
std::string first128(buffer.begin(), buffer.end()); // copy from vector 

Per me sembra che siano diventati un po 'troppo carini con l'implementazione di iostream. Cercare di utilizzare gli iteratori per l'I/O del flusso è eccessivamente complicato.

A proposito, sospetto che l'implementazione che stavate tentando, sotto le copertine, eseguisse una varietà di buffering intermedio (forse alcuni nel kernel, alcuni nella libreria) oltre a riassegnare e copiare la stringa più volte man mano che cresce.

Un'altra idea: hai davvero bisogno del risultato in una stringa standard? Si potrebbe semplicemente lavorare dal vettore - evitando il passaggio finale di copiare su una stringa. Oppure, se ti senti avventuroso, potresti creare la tua classe di stringhe che compie consentendoti di esporre il buffer interno nello stesso modo in cui lo fa il vettore.

+0

Will std :: string fornisce accesso in scrittura a un buffer contiguo in C++ 0x? – nobar

+0

il vettore di char per buffer è una pessima idea veeeery, molto inefficace. – Alecs

+0

@Alecs: potresti elaborare un po '? Vuoi dire che non funzionerà, o semplicemente che non è il metodo più efficiente? – nobar

0

qui ho alcuni di ricerca sopra streambuffer, leggere direttamente alla stringa dal istream dal costruttore:

class mystringbuf : public std::stringbuf 
{ 
public: 
    explicit mystringbuf(std::istream& istr, size_t n, 
         std::ios_base::openmode __mode = std::ios_base::in) 
    { 
     _M_string.resize(n); 
     std::stringbuf::_M_stringbuf_init(__mode); 
     istr.read(gptr(), n); 
    } 
public: 
    std::stringbuf::char_type* gptr() const 
    { 
     return std::stringbuf::gptr(); 
    } 
    std::string& str_ref(){ 
     return _M_string; 
    } 
}; 
std::ostream& operator << (std::ostream& ostr, mystringbuf& buf){ 
    ostr << buf.str_ref(); 
    return ostr; 
} 

Esempio d'uso:

using std::cout; 
using std::endl; 

int main() 
{ 
    std::stringbuf buffer;   // empty buffer 
    buffer.str("abc def ABC DEF "); // not empty now 
    std::istream is (&buffer);  // associate stream buffer to stream 
    mystringbuf data(is, 10);  // read 10 bytes 
    cout << "data=" << data << endl; 
    return 0; 
} 

uscita:

data=abc def AB 

prega inoltrami se sono da qualche parte sbagliata.