2010-11-03 11 views
6

C'est ce que je l'ai essayé jusqu'à présent, mais sans succès:lecture d'un flux de fichier partiel dans une chaîne à l'aide itérateurs

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

Je sais comment lire le fichier entier.

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

Mais ce n'est pas ce que je veux faire. Je reçois une chaîne vide. Si je regarde d'abord et dernier dans un débogueur, ils pointent vers la même chose même après le std :: advance.

+0

Quel est le résultat réel que vous vois-tu? Aussi, s'il vous plaît poster le * real * code que vous avez utilisé. Le code ci-dessus ne compile même pas (EDIT: avant que Charles ne le fixe ...). –

+0

Ok corrigé l'erreur de compilation. Désolé c'était mon mauvais. Je tapais de ma tête. –

+0

Pas besoin d'utiliser HTML, la démarque fonctionne très bien. –

Répondre

5

Y a-t-il une raison particulière pour laquelle vous voulez utiliser des itérateurs? Vous pouvez simplement lire les octets en une seule fois:

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

Si vous voulez vraiment lire les itérateurs, vous pouvez le faire:

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

Non, ce n'est pas nécessaire. Mais j'aimerais savoir si c'est possible. Merci pour la réponse –

+2

'file.read (& s [0], size)' est non portable et dangereux. basic_string n'a pas la garantie de stockage contigu de vector. –

+0

@Steve: Pour quelle implémentation est-ce vrai? –

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

istreambuf_iterators sont entrées itérateurs. Une fois que vous avancez en dernier, l'autre itérateur est également modifié. Vous les traitez comme des itérateurs avant, qui ont la propriété de pouvoir copier un itérateur, de l'avancer, puis d'obtenir une séquence identique en avançant la copie.

Pour le cas général:

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

Cependant, dans ce cas, vous seriez mieux redimensionner la chaîne, en utilisant istream :: lire directement dans & résultat [0], et enfin vérifier que vous lisez le nombre de caractères souhaité.

+0

Mais y a-t-il un moyen de faire quelque chose de similaire en utilisant des itérateurs, ou d'obtenir un itérateur avant d'un ifstream? –

+0

@Allen_SM: Bien sûr, vous pouvez utiliser des itérateurs, j'ai déjà inclus copy_n. Vous pouvez écrire un type d'itérateur pour istreams qui est un itérateur avant (puisque les istreams ont une méthode seekg), mais ce n'est pas nécessaire. –

1

Il n'y a pas d'algorithme standard qui peut vous aider, mais vous pouvez utiliser celui-ci:

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

Cela peut être utilisé avec ReadPartial comme ceci:

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