2010-08-22 13 views
8

Comment lire exactement 128 octets d'un fstream dans un objet chaîne?comment puis-je lire exactement 128 octets d'un fstream dans un objet chaîne?

J'ai écrit du code pour lire les 128 premiers octets d'un fichier et l'imprimer, puis les 128 derniers octets du fichier et l'imprimer. La dernière partie fonctionne, puisque vous pouvez facilement parcourir jusqu'à EOF, mais comment puis-je obtenir exactement 128 octets de l'avant? Le code ci-dessous ne fonctionne pas puisque vous ne pouvez pas ajouter 128 à un itérateur ifstream, ce n'est pas indexable, seulement incrémentable (il semble).

Bien sûr, je pourrais faire un itérateur et * ++ 128 fois, mais il doit y avoir une seule ligne simple pour le faire, non?

#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

Qu'en est-il de istream :: readsome? – Chubsdad

+0

read/readsome ne fonctionne que sur char * s et vous ne pouvez pas obtenir un char * (seulement un const char *) d'un type de chaîne, donc vous ne pouvez pas lire directement dans un type de chaîne avec eux. –

Répondre

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

Qu'en est-ce alors:

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! char tampon [128]; ifs.read (tampon, 128); std :: string first128 (tampon, 128); Mais vraiment, je veux le faire aussi purement que possible. Les réponses sans équerres ne doivent pas s'appliquer! –

+0

@Southern Hospitality: J'ai modifié pour inclure une autre version. – ngoozeff

+0

Je pense que la première réponse est parfaite. Vous voulez entrer dans une chaîne, créez simplement une chaîne std :: de taille 128 et passez la comme la mémoire tampon à lire. Penser que ce n'est pas pur indique que la bibliothèque standard est en quelque sorte impure. –

0

Ma réponse utilise un tampon intermédiaire, mais peut-être vous serez heureux qu'il utilise itérateurs pour initialiser la chaîne de la mémoire tampon.

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 

Pour moi, il semble qu'ils soient un peu trop mignons avec l'implémentation d'iostreams. Essayer d'utiliser des itérateurs pour les E/S de flux est trop compliqué. A propos, je suspecte que l'implémentation que vous essayiez fera, sous les couvertures, une variété de tampons intermédiaires (peut-être dans le noyau, certains dans la bibliothèque) ainsi que la réaffectation et la copie de la chaîne plusieurs fois à mesure qu'il grandit.

Une autre idée: Avez-vous vraiment besoin du résultat dans une chaîne standard? Vous pourriez juste travailler à partir du vecteur - en évitant la dernière étape de la copie à une chaîne. Ou, si vous vous sentez aventureux, vous pouvez créer votre propre classe de chaînes que vous permet d'exposer le tampon interne de la même manière que le vecteur.

+0

Est-ce que std :: string fournira un accès en écriture à un tampon contigu en C++ 0x? – nobar

+0

vecteur de char pour tampon est veeeery mauvaise idée, très inefficace. – Alecs

+0

@Alecs: Pourriez-vous élaborer un peu? Voulez-vous dire que ça ne marchera pas ou que ce n'est pas la méthode la plus efficace? – nobar

0

Ici, j'ai un peu de recherche sur streambuffer, lire directement sur la chaîne de istream par constructeur:

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

Exemple d'utilisation:

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

Sortie:

data=abc def AB 

S'il vous plaît envoyez-moi si je suis quelque part avait tort.