Read text file into std::string. | | |
Does this function need to call eof after the while-loop to be correct?
bool read_file(std::string name, std::string &s)
{
std::ifstream in(name.c_str());
if (!in.is_open())
return false;
char c;
std::string str;
while (in.get(c))
str += c;
if (!in.eof())
return false;
s = str;
return true;
}
Thanks. | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
> Does this function need to call eof after the while-loop to be correct?
>
> bool read_file(std::string name, std::string &s)
> {
> std::ifstream in(name.c_str());
> if (!in.is_open())
> return false;
>
> char c;
> std::string str;
> while (in.get(c))
> str += c;
>
> if (!in.eof())
> return false;
>
> s = str;
> return true;
> }
>[/color]
Calling EOF after the loop here is a check to insure that you exited
the loop because you read to the end of the file. There are a few other
reasons that get() might not be able to read a char and return a count
of 0. | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
> Does this function need to call eof after the while-loop to be correct?[/color]
Yes.
[color=blue]
> bool read_file(std::string name, std::string &s)
> {
> std::ifstream in(name.c_str());
> if (!in.is_open())
> return false;
>
> char c;
> std::string str;
> while (in.get(c))
> str += c;[/color]
This loop is _extremely_ slow (or do you want to prove the
impracticality of C++?). Use getline (in, str) instead.
[color=blue]
> if (!in.eof())
> return false;
>
> s = str;[/color]
s.swap(str);
[color=blue]
> return true;
> }[/color] | | | | re: Read text file into std::string.
> Does this function need to call eof after the while-loop to be correct?
Depends. The stream can terminate that while loop for a number of
reasons including a bad harddrive or an out of memory condition, etc.
If you want to make sure it read all the characters all the way to end
of the file, you have to check if it exited the loop because due to
eof.
[color=blue]
> bool read_file(std::string name, std::string &s)
> {
> std::string str;[/color]
<snip>
[color=blue]
> s = str;[/color]
btw, if this is your code, I suggest you do s.swap(str) instead of the
assignment. | | | | re: Read text file into std::string.
"Jason Heyes" <jasonheyes@optusnet.com.au> wrote in message
news:42a7e664$0$10697$afc38c87@news.optusnet.com.a u...[color=blue]
> Does this function need to call eof after the while-loop to be correct?
>
> bool read_file(std::string name, std::string &s)
> {
> std::ifstream in(name.c_str());
> if (!in.is_open())
> return false;
>
> char c;
> std::string str;
> while (in.get(c))
> str += c;
>
> if (!in.eof())
> return false;
>
> s = str;
> return true;
> }
>
> Thanks.
>
>[/color]
Why not extract the file's contents into a container of strings? If you make
the container a member of a class, read_file() and a write_file() could be
member functions of that class with access to the encapsulated container.
There are a number of other ways this could be done. You might overload the
write() member function so it takes a reference to another string container
to write to file, you might choose to use the same filestream to read /
write, etc.
// FileParser.cpp
//
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <stdexcept>
class FileParser
{
// members
const std::string m_filename_;
std::string m_buffer;
std::ifstream m_ifs;
std::ofstream m_ofs;
std::vector<std::string> m_vs;
public:
// ctor
FileParser(std::string s)
: m_filename_(s), m_buffer(), m_ifs(), m_ofs(), m_vs() { }
~FileParser() { }
// read() member function
void read() throw(std::exception)
{
m_ifs.open(m_filename_.c_str(), std::ios::in);
if (!m_ifs)
{
throw std::exception("error opening file for read().\n");
}
while (std::getline(m_ifs, m_buffer))
{
m_vs.push_back(m_buffer);
}
if (!m_ifs.eof()) // if reason of termination != eof
{
throw std::exception("error while parsing file.\n");
}
}
// write(...) member function
void write() throw(std::exception)
{
m_ofs.open(m_filename_.c_str());
if (!m_ofs)
{
throw std::exception("error opening file for write().\n");
}
// copy algorithm with ostream_iterator
std::copy( m_vs.begin(),
m_vs.end(),
std::ostream_iterator<std::string>(m_ofs, "\n") );
}
// load(...) member function
void load(std::vector<std::string>& r_vs)
{
m_vs.clear();
std::copy(r_vs.begin(), r_vs.end(), std::back_inserter(m_vs));
}
// display() member function
void display() const
{
std::cout << "\n--- FileParse::display() ---\n\n";
std::copy( m_vs.begin(),
m_vs.end(),
std::ostream_iterator<std::string>(std::cout,
"\n") );
}
}; // class FileParser
int main()
{
std::vector<std::string> vstrings;
vstrings.push_back("string 0");
vstrings.push_back("string 1");
vstrings.push_back("string 2");
vstrings.push_back("string 3");
vstrings.push_back("string 4");
// FileParser object
FileParser fileparser("file.dat");
fileparser.load(vstrings);
fileparser.display();
try
{
fileparser.write();
fileparser.read();
fileparser.display();
}
catch (const std::exception& e)
{
std::cout << "Error:\n";
std::cout << e.what();
}
return 0;
} // main()
/* file.dat
--- FileParse::display() ---
string 0
string 1
string 2
string 3
string 4
*/ | | | | re: Read text file into std::string.
"Rapscallion" <raps72583m@spambob.com> wrote in message
news:1118306653.085178.299820@o13g2000cwo.googlegr oups.com...[color=blue]
> Jason Heyes wrote:[color=green]
>>
>> char c;
>> std::string str;
>> while (in.get(c))
>> str += c;[/color]
>
> This loop is _extremely_ slow (or do you want to prove the
> impracticality of C++?). Use getline (in, str) instead.
>[/color]
Why is the loop slow? Isn't get inlined?
I read that getline needs a count of the number of elements to extract and
an array to store them. It does not take std::string. So how can I use
getline instead of get in this function? | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
> "Rapscallion" <raps72583m@spambob.com> wrote in message
> news:1118306653.085178.299820@o13g2000cwo.googlegr oups.com...[color=green]
> > Jason Heyes wrote:[color=darkred]
> >>
> >> char c;
> >> std::string str;
> >> while (in.get(c))
> >> str += c;[/color]
> >
> > This loop is _extremely_ slow (or do you want to prove the
> > impracticality of C++?). Use getline (in, str) instead.
> >[/color]
>
> Why is the loop slow? Isn't get inlined?
>
> I read that getline needs a count of the number of elements to extract and
> an array to store them. It does not take std::string. So how can I use
> getline instead of get in this function?[/color]
getline(in, str);
This reads the data until it finds either EOF, '\n' or max amount of
data that can be read is read (to check the last you need to see if the
fail bit is set).
It doesn't copy the '\n' (or EOF) into the string but it does extract
it so the code should be:
getline(in, str);
str+= '\n'; | | | | re: Read text file into std::string.
Peter Julian wrote:[color=blue]
> Why not extract the file's contents into a container of strings? If you make
> the container a member of a class, read_file() and a write_file() could be
> member functions of that class with access to the encapsulated container.
>
> There are a number of other ways this could be done. You might overload the
> write() member function so it takes a reference to another string container
> to write to file, you might choose to use the same filestream to read /
> write, etc.[/color]
Your FileParser is done well but the design is not perfect. Some
remarks are attached. Refactoring the design is recommended.
[color=blue]
> // FileParser.cpp
> //
> #include <iostream>
> #include <string>
> #include <fstream>
> #include <vector>
> #include <algorithm>
> #include <stdexcept>
>
> class FileParser
> {
> // members
> const std::string m_filename_;
> std::string m_buffer;
> std::ifstream m_ifs;
> std::ofstream m_ofs;[/color]
These need not be members.
[color=blue]
> std::vector<std::string> m_vs;[/color]
Use std::list to avoid unnecessary copies of strings (each copy > 16
means dynamic allocation on VC 7.1)
std::vector<std::string> m_vlist;
[color=blue]
> public:
> // ctor
> FileParser(std::string s)
> : m_filename_(s), m_buffer(), m_ifs(), m_ofs(), m_vs() { }
> ~FileParser() { }
>
> // read() member function
> void read() throw(std::exception)
> {
> m_ifs.open(m_filename_.c_str(), std::ios::in);
> if (!m_ifs)
> {
> throw std::exception("error opening file for read().\n");
> }
> while (std::getline(m_ifs, m_buffer))
> {
> m_vs.push_back(m_buffer);[/color]
m_vlist.resize (m_vlist.size() +1);
m_vlist.back().swap (m_buffer);
[color=blue]
> }
> if (!m_ifs.eof()) // if reason of termination != eof
> {
> throw std::exception("error while parsing file.\n");
> }
> }
>
> // write(...) member function
> void write() throw(std::exception)[/color]
void write (std::ostream& os) // write to any ostream
[color=blue]
> {
> m_ofs.open(m_filename_.c_str());
> if (!m_ofs)
> {
> throw std::exception("error opening file for write().\n");
> }
> // copy algorithm with ostream_iterator
> std::copy( m_vs.begin(),
> m_vs.end(),
> std::ostream_iterator<std::string>(m_ofs, "\n") );
> }
>
> // load(...) member function
> void load(std::vector<std::string>& r_vs)[/color]
why this???
[color=blue]
> {
> m_vs.clear();
> std::copy(r_vs.begin(), r_vs.end(), std::back_inserter(m_vs));
> }[/color]
[color=blue]
> // display() member function
> void display() const[/color]
friend
std::ostream& operator<< (std::ostream& os, const FileParser& f);
[color=blue]
> {
> std::cout << "\n--- FileParse::display() ---\n\n";
> std::copy( m_vs.begin(),
> m_vs.end(),
> std::ostream_iterator<std::string>(std::cout,
> "\n") );
> }
>
> }; // class FileParser
>
> int main()
> {
> std::vector<std::string> vstrings;
> vstrings.push_back("string 0");
> vstrings.push_back("string 1");
> vstrings.push_back("string 2");
> vstrings.push_back("string 3");
> vstrings.push_back("string 4");
>
> // FileParser object
> FileParser fileparser("file.dat");
> fileparser.load(vstrings);
> fileparser.display();
>
> try
> {
> fileparser.write();
>
> fileparser.read();
> fileparser.display();
> }
> catch (const std::exception& e)
> {
> std::cout << "Error:\n";
> std::cout << e.what();
> }
>
> return 0;
>
> } // main()
>
> /* file.dat
>
> --- FileParse::display() ---
>
> string 0
> string 1
> string 2
> string 3
> string 4
>
> */[/color] | | | | re: Read text file into std::string.
Jason Heyes wrote:
[color=blue]
>
> Why is the loop slow? Isn't get inlined?
>[/color]
It's inlined probably, but still moves one character at a time
fom the stream and grows the string one element at a time with it.
[color=blue]
> I read that getline needs a count of the number of elements to extract and
> an array to store them. It does not take std::string. So how can I use
> getline instead of get in this function?
>[/color]
You didn't read far enough. There's a getline that's not a member
of stream that takes a string. | | | | re: Read text file into std::string.
Ron Natalie wrote:
[color=blue]
> Jason Heyes wrote:
>[color=green]
>>
>> Why is the loop slow? Isn't get inlined?
>>[/color]
> It's inlined probably, but still moves one character at a time
> fom the stream and grows the string one element at a time with it.[/color]
And you think getline does someting else internally? | | | | re: Read text file into std::string.
Rolf Magnus wrote:[color=blue]
> Ron Natalie wrote:[color=green][color=darkred]
> >> Why is the loop slow? Isn't get inlined?
> >>[/color]
> > It's inlined probably, but still moves one character at a time
> > fom the stream and grows the string one element at a time with it.[/color]
>
> And you think getline does someting else internally?[/color]
Yes! | | | | re: Read text file into std::string.
"Rapscallion" <raps72583m@spambob.com> wrote in message
news:1118314951.547244.253050@z14g2000cwz.googlegr oups.com...[color=blue]
> Rolf Magnus wrote:[color=green]
>> Ron Natalie wrote:[color=darkred]
>> >> Why is the loop slow? Isn't get inlined?
>> >>
>> > It's inlined probably, but still moves one character at a time
>> > fom the stream and grows the string one element at a time with it.[/color]
>>
>> And you think getline does someting else internally?[/color]
>
> Yes!
>[/color]
Do you mind explaining how? :P | | | | re: Read text file into std::string.
<velthuijsen@hotmail.com> wrote in message
news:1118311450.731110.134140@o13g2000cwo.googlegr oups.com...[color=blue]
> getline(in, str);
>
> This reads the data until it finds either EOF, '\n' or max amount of
> data that can be read is read (to check the last you need to see if the
> fail bit is set).
> It doesn't copy the '\n' (or EOF) into the string but it does extract
> it so the code should be:
> getline(in, str);
> str+= '\n';
>[/color]
Do you mind writing the loop as well? I can't see what you are doing.
You get an extra newline character added to the end of str with that code. | | | | re: Read text file into std::string.
> Do you mind writing the loop as well? I can't see what you are doing.[color=blue]
> You get an extra newline character added to the end of str with that code.[/color]
It wasn't meant as a complete function, just a comment on how to work
with it.
And yes you need that extra newline since the getline function doesn't
add it to the string but it does remove it from the stream.
But if you want a while loop, here is the whole function.
bool read_file(std::string name, std::string &s)
{
std::ifstream in(name.c_str());
if (!in.is_open())
{
return false;
}
std::string str;
while(in.good())
{
// guard against reading '\n' and then EOF
if (std::char_traits<char>::eof() != in.peek())
{
break;
}
getline(in, str);
str+= '\n';
}
if (!in.eof())
{
return false;
}
s.swap(str);
return true;
} | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
> Do you mind explaining how? :P[/color]
Just don't add charactes one by one to the string. Do it in larger
chunks. | | | | re: Read text file into std::string.
Rapscallion wrote:[color=blue]
> Jason Heyes wrote:[color=green]
> > Do you mind explaining how? :P[/color]
>
> Just don't add charactes one by one to the string. Do it in larger
> chunks.[/color]
Or how about just:
std::string text;
text << fileStream.rdbuf();
This seems most straightforward to me. No need to mess with loops and
what not.
-shez- | | | | re: Read text file into std::string.
Shezan Baig wrote:[color=blue]
> Or how about just:
> std::string text;
>
> text << fileStream.rdbuf();
>
> This seems most straightforward to me. No need to mess with loops and
> what not.[/color]
The 'mess with loops' and 'text << fileStream.rdbuf()' produce the same
result? Really? | | | | re: Read text file into std::string.
"Shezan Baig" <shezanbaig2004@gmail.com> wrote in message
news:1118348371.094683.200670@g49g2000cwa.googlegr oups.com...[color=blue]
>
>
> Rapscallion wrote:[color=green]
>> Jason Heyes wrote:[color=darkred]
>> > Do you mind explaining how? :P[/color]
>>
>> Just don't add charactes one by one to the string. Do it in larger
>> chunks.[/color]
>
>
> Or how about just:
>
> std::string text;
>
> text << fileStream.rdbuf();
>
> This seems most straightforward to me. No need to mess with loops and
> what not.
>[/color]
How can that work? It looks like you were trying to write:
is.rdbuf() >> text;
This does not work. | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
> How can that work? It looks like you were trying to write:
>
> is.rdbuf() >> text;
>
> This does not work.[/color]
Sorry, wasn't thinking. It should be:
std::stringstream ss;
ss << is.rdbuf();
now you can do whatever you want with 'ss.str()'.
hth,
-shez- | | | | re: Read text file into std::string.
"Shezan Baig" <shezanbaig2004@gmail.com> wrote in message
news:1118404954.848885.176870@z14g2000cwz.googlegr oups.com...[color=blue]
>
>
> Jason Heyes wrote:[color=green]
>> How can that work? It looks like you were trying to write:
>>
>> is.rdbuf() >> text;
>>
>> This does not work.[/color]
>
>
> Sorry, wasn't thinking. It should be:
>
> std::stringstream ss;
>
> ss << is.rdbuf();
>
> now you can do whatever you want with 'ss.str()'.
>[/color]
Hey it works! Thanks for the neat trick. | | | | re: Read text file into std::string.
"Shezan Baig" <shezanbaig2004@gmail.com> wrote in message
news:1118404954.848885.176870@z14g2000cwz.googlegr oups.com...[color=blue]
>
>
> Jason Heyes wrote:[color=green]
>> How can that work? It looks like you were trying to write:
>>
>> is.rdbuf() >> text;
>>
>> This does not work.[/color]
>
>
> Sorry, wasn't thinking. It should be:
>
> std::stringstream ss;
>
> ss << is.rdbuf();
>
> now you can do whatever you want with 'ss.str()'.
>[/color]
Here in.eof() equals false:
bool read_file(std::string name, std::string &s)
{
std::ifstream in(name.c_str());
if (!in.is_open())
return false;
std::stringstream ss;
ss << in.rdbuf();
if (!in.eof())
return false;
s = ss.str();
return true;
}
When a loop is used, in.eof() equals true. Why the difference? | | | | re: Read text file into std::string.
Jason Heyes wrote:[color=blue]
>
> Here in.eof() equals false:
>
> bool read_file(std::string name, std::string &s)
> {
> std::ifstream in(name.c_str());
> if (!in.is_open())
> return false;
>
> std::stringstream ss;
> ss << in.rdbuf();
>
> if (!in.eof())
> return false;
>
> s = ss.str();
> return true;
> }
>
> When a loop is used, in.eof() equals true. Why the difference?[/color]
Because this code reads from the filebuf, which has no notion of eof,
badbit etc. If you need to check eof or other failures, you can do it
the other way round:
is >> ss.rdbuf();
hth,
-shez- | | | | re: Read text file into std::string.
"Shezan Baig" <shezanbaig2004@gmail.com> wrote in message
news:1118409984.841215.232050@g43g2000cwa.googlegr oups.com...[color=blue]
> Jason Heyes wrote:[color=green]
>>
>> Here in.eof() equals false:
>>
>> bool read_file(std::string name, std::string &s)
>> {
>> std::ifstream in(name.c_str());
>> if (!in.is_open())
>> return false;
>>
>> std::stringstream ss;
>> ss << in.rdbuf();
>>
>> if (!in.eof())
>> return false;
>>
>> s = ss.str();
>> return true;
>> }
>>
>> When a loop is used, in.eof() equals true. Why the difference?[/color]
>
>
> Because this code reads from the filebuf, which has no notion of eof,
> badbit etc. If you need to check eof or other failures, you can do it
> the other way round:
>
> is >> ss.rdbuf();
>[/color]
I tried this with the eof checking enabled. I lost all "\n\t" sequences.
Very peculiar. |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,471 network members.
|