By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,433 Members | 1,842 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,433 IT Pros & Developers. It's quick & easy.

Reading items from a text file to a vector

P: n/a
zr
Hi,

i need to read a text file which contains a list of items, all of type
ItemType, separated by whitespace and newlines. For each line, there
will be a vector<ItemTypeobject that will store the integers read in
that line. There will be a single vector<vector<ItemType>object that
will stores all of the vector<ItemTypeobjects mentioned in the
previous sentence.
I wrote a quick implementation and it seems to be working, but i would
like to hear some opinions on what may be incorrect or may be
improved, especially exception and runtime error handling. Assume that
the required operator>in code line 13 is defined.

TIA

1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
3 while (source.good()) {
4 string s;
5 getline(source, s, '\n');
6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemTypet;
10
11 while (iss.good()) {
12 ItemType item;
13 iss >item;
14 t.push_back(item);
15 }
16 db.push_back(t);
17 }
18}

Nov 14 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
zr wrote:
Hi,

i need to read a text file which contains a list of items, all of type
ItemType, separated by whitespace and newlines. For each line, there
will be a vector<ItemTypeobject that will store the integers read in
that line. There will be a single vector<vector<ItemType>object that
will stores all of the vector<ItemTypeobjects mentioned in the
previous sentence.
I wrote a quick implementation and it seems to be working, but i would
like to hear some opinions on what may be incorrect or may be
improved, especially exception and runtime error handling. Assume that
the required operator>in code line 13 is defined.
Don't use line numbers in your posts. It makes it difficult for
readers to cut&paste your code.
Correction on your line2 and on your lines 11-15.

>
1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
vector<vector<ItemType& db
3 while (source.good()) {
4 string s;
5 getline(source, s, '\n');
6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemTypet;
10
11 while (iss.good()) {
12 ItemType item;
13 iss >item;
14 t.push_back(item);
15 }
for (ItemType item; iss >item; )
t.push_back(item);

16 db.push_back(t);
17 }
18}
Nov 14 '08 #2

P: n/a
red floyd wrote:
zr wrote:
>Hi,

i need to read a text file which contains a list of items, all of type
ItemType, separated by whitespace and newlines. For each line, there
will be a vector<ItemTypeobject that will store the integers read in
that line. There will be a single vector<vector<ItemType>object that
will stores all of the vector<ItemTypeobjects mentioned in the
previous sentence.
I wrote a quick implementation and it seems to be working, but i would
like to hear some opinions on what may be incorrect or may be
improved, especially exception and runtime error handling. Assume that
the required operator>in code line 13 is defined.
Don't use line numbers in your posts. It makes it difficult for
readers to cut&paste your code.
Correction on your line2 and on your lines 11-15.
Forgot the correction on 3-5.
>
>>
1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
vector<vector<ItemType& db
>3 while (source.good()) {
4 string s;
5 getline(source, s, '\n');
for (string s; getline(source, s); ) // '\n' is implied
>6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemTypet;
10
>11 while (iss.good()) {
12 ItemType item;
13 iss >item;
14 t.push_back(item);
15 }
for (ItemType item; iss >item; )
t.push_back(item);

>16 db.push_back(t);
17 }
18}
Nov 14 '08 #3

P: n/a
On Nov 14, 2:00 am, zr <zvir...@gmail.comwrote:
i need to read a text file which contains a list of items, all
of type ItemType, separated by whitespace and newlines. For
each line, there will be a vector<ItemTypeobject that will
store the integers read in that line. There will be a single
vector<vector<ItemType>object that will stores all of the
vector<ItemTypeobjects mentioned in the previous sentence.
I wrote a quick implementation and it seems to be working, but
i would like to hear some opinions on what may be incorrect or
may be improved, especially exception and runtime error
handling. Assume that the required operator>in code line 13
is defined.
As you've posted it, it won't compile:-). But in fact, it isn't
guaranteed to work, even with the correction to the syntax.
1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
">>" is a shift left operator, and doesn't close two open template
lists; you need "" (unless your compiler has already
implemented this feature of the next version of the standard).
3 while (source.good()) {
And this is an error; source.good() does NOT mean that the next
input is guaranteed to succeed. (In practice, what will
probably happen is that you'll get an extra, empty list at the
end of your results.)
4 string s;
5 getline(source, s, '\n');
6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemTypet;
10
11 while (iss.good()) {
Same thing here. Most of the time, this will work anyway, but
if you have a line which contains trailing white space, it may
result in an additional default constructed item at the end of
the list.
12 ItemType item;
13 iss >item;
14 t.push_back(item);
15 }
16 db.push_back(t);
17 }
18}
In general, you should always test *after* reading from a
stream, to know if the input succeeded or failed. And be wary
of the names of the status functions in the streams; they are
very misleading. (I've never found a use for good(), for
example.) Taking this into account, your code should probably
look something like:

std::string s ;
while ( std::getline( source, s ) ) {
std::istringstream iss( s ) ;
std::vector< ItemType >
t ;
ItemType item ;
while ( iss >item ) {
t.push_back( item ) ;
}
db.push_back( t ) ;
}

In addition, you might want to think about other possible input
errors: what happens if an item in the file is misformatted.
(You can typically detect this by checking iss.eof() after the
inner loop above; if input failed and you don't have eof() or
bad(), then you have a formatting error.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Nov 14 '08 #4

P: n/a
zr wrote:
Hi,

i need to read a text file which contains a list of items, all of type
ItemType, separated by whitespace and newlines. For each line, there
will be a vector<ItemTypeobject that will store the integers read in
that line. There will be a single vector<vector<ItemType>object that
will stores all of the vector<ItemTypeobjects mentioned in the
previous sentence.
I wrote a quick implementation and it seems to be working, but i would
like to hear some opinions on what may be incorrect or may be
improved, especially exception and runtime error handling. Assume that
the required operator>in code line 13 is defined.

TIA

1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
3 while (source.good()) {
4 string s;
5 getline(source, s, '\n');
6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemTypet;
10
11 while (iss.good()) {
12 ItemType item;
13 iss >item;
14 t.push_back(item);
15 }
16 db.push_back(t);
17 }
18}
You have received some suggestions so far. The following is radically
different: (a) globally and (b) locally.

(a) The two problems of converting a single line and converting a whole file
are intermingled in your solution. I suggest taking those issues apart.
Also, you deal with vectors of vectors specifically. I think, one can be
more general.

(b) Just for fun, I used iterators and standard algorithms. Two different
methods of error reporting are employed: exceptions if there is no stream
to return or the status bits of the stream if present.

Here goes:

#include <iostream>
#include <istream>
#include <string>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <stdexcept>

struct line : public std::string {};

std::istream & operator>( std::istream & istr, line & l ) {
return ( std::getline( istr, l ) );
}

template < typename Sequence >
Sequence scan_line ( std::string const & l ) {
std::istringstream istr ( l );
Sequence result;
typedef typename Sequence::value_type value_type;
std::copy( std::istream_iterator< value_type >( istr ),
std::istream_iterator< value_type >(),
std::back_inserter( result ) );
if ( ! istr.eof() || istr.bad() ) {
throw ( std::invalid_argument( "line invalid\n" ) );
}
return ( result );
}

template < typename Sequence >
std::istream & collect ( std::istream & istr, Sequence & seq ) {
typedef typename Sequence::value_type value_type;
std::transform( std::istream_iterator< line >( istr ),
std::istream_iterator< line >(),
std::back_inserter( seq ),
& scan_line< value_type );
return ( istr );
}

int main ( void ) {
std::vector< std::vector<int ivv;
try {
collect( std::cin, ivv );
if ( std::cin.eof() && ! std::cin.bad() ) {
for ( unsigned long n = 0; n < ivv.size(); ++n ) {
for ( unsigned long m = 0; m < ivv[n].size(); ++m ) {
std::cout << ivv[n][m] << " ";
}
std::cout << "\n";
}
} else {
std::cerr << "File format error\n";
}
}
catch ( std::invalid_argument const & i ) {
std::cerr << i.what();
}
}
BTW: I do not claim that this is "better". I just think you should know that
there are many ways to go about this.
Best

Kai-Uwe Bux
Nov 15 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.