C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

reading entire file to a string

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Paul Rosen
Guest





PostPosted: Fri Nov 18, 2005 12:09 am    Post subject: reading entire file to a string Reply with quote



I have some old code (that works just fine!), but it uses FILE* and
CString to read the contents of a relatively small file to a string in a
single call. Its signature is:

bool ReadFileToString(const CString& csFilename, CString& csContents);

I'd like to change that, though, to use std::string and std:ifstream.
The routine should be as efficient as possible with little copying of data.

I'd like the signature of the routine to be:

bool ReadFileToString(const std::string& strFilename, std::string&
strContents);

The approach that occurs to me is:

0) open the file in binary mode
1) seek to the end of the file to get the length
2) resize a stack variable of type std::vector<char> to the length
3) seek back to the beginning
4) read that many characters into the vector
5) copy the contents of the vector into strContents, translating rn
into n

There has got to be a better way, particularly since the companion
routine was so easy.

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
ifs << strContents;
}

Any suggestions?

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Carl Barron
Guest





PostPosted: Fri Nov 18, 2005 10:28 am    Post subject: Re: reading entire file to a string Reply with quote



In article <l63ff.1310$wf.1155 (AT) newsread3 (DOT) news.atl.earthlink.net>, Paul
Rosen <prosen (AT) fte (DOT) com> wrote:

Quote:
I have some old code (that works just fine!), but it uses FILE* and
CString to read the contents of a relatively small file to a string in a
single call. Its signature is:

bool ReadFileToString(const CString& csFilename, CString& csContents);

I'd like to change that, though, to use std::string and std:ifstream.
The routine should be as efficient as possible with little copying of data.

I'd like the signature of the routine to be:

bool ReadFileToString(const std::string& strFilename, std::string&
strContents);

The approach that occurs to me is:

0) open the file in binary mode
1) seek to the end of the file to get the length
2) resize a stack variable of type std::vector<char> to the length
3) seek back to the beginning
4) read that many characters into the vector
5) copy the contents of the vector into strContents, translating rn
into n

There has got to be a better way, particularly since the companion
routine was so easy.

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
ifs << strContents;
}

quickest to write:
inline void file_to_string(std::istream &in,std::string &out)
{
std::copy
(
std::istreambuf_iterator std::istreambuf_iterator<char>(),
std::back_inserter(out)
);
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
G.J. Giezeman
Guest





PostPosted: Fri Nov 18, 2005 1:24 pm    Post subject: Re: reading entire file to a string Reply with quote



Paul Rosen wrote:
Quote:
I have some old code (that works just fine!), but it uses FILE* and
CString to read the contents of a relatively small file to a string in a
single call. Its signature is:

bool ReadFileToString(const CString& csFilename, CString& csContents);

I'd like to change that, though, to use std::string and std:ifstream.
The routine should be as efficient as possible with little copying of data.

I'd like the signature of the routine to be:

bool ReadFileToString(const std::string& strFilename, std::string&
strContents);

My suggestion: use the istreambuf_iterator.

#include <fstream>
#include <string>
#include <iterator>

bool ReadFileToString(const std::string& strFilename, std::string&
strContents)
{
typedef std::istreambuf_iterator<char> stream_iter;
std::ifstream is(strFilename.c_str());
if (!is)
return false;
strContents.assign(stream_iter(is),stream_iter());
return true;
}


Quote:
There has got to be a better way, particularly since the companion
routine was so easy.

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
ifs << strContents;
}

I guess you meant using an ofstream here.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Yuri Khan
Guest





PostPosted: Fri Nov 18, 2005 1:25 pm    Post subject: Re: reading entire file to a string Reply with quote

Paul Rosen wrote:
Quote:
I have some old code (that works just fine!), but it uses FILE* and
CString to read the contents of a relatively small file to a string in a
single call. Its signature is:

I'd like the signature of the routine to be:

bool ReadFileToString(const std::string& strFilename, std::string&
strContents);

The approach that occurs to me is:

0) open the file in binary mode
1) seek to the end of the file to get the length
2) resize a stack variable of type std::vector<char> to the length
3) seek back to the beginning
4) read that many characters into the vector
5) copy the contents of the vector into strContents, translating rn
into n

There has got to be a better way, particularly since the companion
routine was so easy.

If you can live with the fact that the target string will be
reallocated several times (usually log(N) times, where N is the file
size), you might want to try std::getline(basic_istream<charT, traits>&
is, basic_string<charT, traits, Allocator>& str, charT delim), passing
in a delimiter character that is guaranteed not to occur in the file.
Seeing as you want to translate rn into n, I assume your file is
text, so the NUL character (0x00) will probably suit you.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Pramod
Guest





PostPosted: Fri Nov 18, 2005 1:26 pm    Post subject: Re: reading entire file to a string Reply with quote

Try this

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
strFilename = std::string ( std::istreambuf_iterator<char>( ifs ),
std::istreambuf_iterator<char>( ) );
}


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze
Guest





PostPosted: Fri Nov 18, 2005 4:40 pm    Post subject: Re: reading entire file to a string Reply with quote

Paul Rosen wrote:
Quote:
I have some old code (that works just fine!), but it uses
FILE* and CString to read the contents of a relatively small
file to a string in a single call. Its signature is:

bool ReadFileToString(const CString& csFilename, CString& csContents);

I'd like to change that, though, to use std::string and
std:ifstream. The routine should be as efficient as possible
with little copying of data.

Is this something the profiler has said?

Quote:
I'd like the signature of the routine to be:

bool ReadFileToString(const std::string& strFilename, std::string&
strContents);

The approach that occurs to me is:

0) open the file in binary mode
1) seek to the end of the file to get the length
2) resize a stack variable of type std::vector<char> to the length
3) seek back to the beginning
4) read that many characters into the vector
5) copy the contents of the vector into strContents, translating rn
into n

If the profiler says you have a performance problem...

If you're translating "rn" into "n", you're probably not
looking for a portable solution. In that case, the obvious
answer is to use system specific requests to get actual file
size, and to do the read, and forget about ifstream completely.

Quote:
There has got to be a better way, particularly since the
companion routine was so easy.

How about something like:

std::string
readFileToString(
std::string const& filename )
{
std::ifstream source( filename.c_str() ) ;
// Error handling needed here...
std::ostringstream result ;
result << source.rdbuf() ;
return result.str() ;
}

Whether the performance is acceptable (for whatever definition
of acceptable) will depend on the implementation, of course.
Practically, however, if you have to go behind the back of the
implementation: your performance depends on the implementation,
even if you use only C++ standard constructs in its
implementation, so you might as well go all the way, and use the
low level system requests. Reading the entire file to get its
length, for example, is likely to be significantly more
expensive that just copying (using std::copy,
istreambuf_iterators and a back_inserter) into an std::string,
especially if you can make a pretty good preliminary guess and
call capacity first. And presumably, the implementation has
optimized the mapping of "rn" into "n" better than you could.

My first try would probably be the above. My second, supposing
the profiler showed this to be a problem, would be:

std::string
readFileToString(
std::string const& filename )
{
std::ifstream source( filename.c_str() ) ;
// Error handling needed here...
return std::string(
(std::istreambuf_iterator (std::istreambuf_iterator<char>()) ) ;
}

Whether this is faster than the precedant will depend on the
implementation, but there are two very simple implementations to
choose from.

This one can also be simply improved by declaring the string
beforehand, then calling reserve on it, and using std::copy and
a back_inserter to insert the data. Or possibly by using
std::vector<char>, then constructing the string from it. But
which solution gives the best results will depend on the
implementation, and can only be determined by measuring.

--
James Kanze GABI Software
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


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
mzdude
Guest





PostPosted: Sat Nov 19, 2005 10:23 am    Post subject: Re: reading entire file to a string Reply with quote


Pramod wrote:
Quote:
Try this

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
strFilename = std::string ( std::istreambuf_iterator<char>( ifs ),
std::istreambuf_iterator<char>( ) );
}

Hmmm... Seems suspiciously like Item 29 from Scott Meyers Effective STL



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Victor Bazarov
Guest





PostPosted: Sat Nov 19, 2005 7:27 pm    Post subject: Re: reading entire file to a string Reply with quote

mzdude wrote:
Quote:
Pramod wrote:
Try this

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ifstream ifs(strFilename);
strFilename = std::string ( std::istreambuf_iterator<char>( ifs
), std::istreambuf_iterator<char>( ) );
}

Hmmm... Seems suspiciously like Item 29 from Scott Meyers Effective
STL

This code has a serious error: an attempt to assign to a const string.
I don't think Scott would let that happen... Perhaps 'Pramod' meant:

void ReadStringFromFile(const std::string& strFilename,
std::string& strContents)
{
std::ifstream ifs(strFilename);
strContents = std::string ( std::istreambuf_iterator<char>( ifs ),
std::istreambuf_iterator<char>( ) );
}

Just a guess...

V



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
fanofvc
Guest





PostPosted: Mon Nov 21, 2005 10:35 am    Post subject: Re: reading entire file to a string Reply with quote

#include <fstream>
#include <iostream>
#include <sstream>
#include <exception>
#include <vector>
#include <string>
using namespace std;
bool ReadFileToString(const std::string& strFilename, std::string&
strContents)
{
fstream fs;
try
{
fs.open(strFilename.c_str(), ios::in|ios::binary );
if(!fs)
{
ostringstream ostr;
ostr << "Cannot open File:" << strFilename << "!" << endl;
string ostrMsg = ostr.str();
throw runtime_error(ostrMsg);
}

}
catch ( runtime_error &e )
{
cout << e.what() << endl;
return false;
}
fs.seekg(0,ios::beg);
streampos begin = fs.tellg();
fs.seekg(0,ios::end);
streampos end = fs.tellg();
size_t nLength = end-begin;
vector fs.seekg(0,ios::beg);
char p;
int iLen = 0;
while(fs.get(p))
{
vecFileContent[iLen++] = p;

}


vector <char>::iterator iter = vecFileContent.begin();

while(iter!=vecFileContent.end())
{
if(static_cast<int>(*iter)=='0x0d' &&static_cast<int>(*(iter+1))
== '0x0a')
{
strContents.push_back(*(++iter++));
}
else
{
strContents.push_back(*(iter++));
}

}



fs.close();
return true;
}

void WriteStringToFile(const std::string& strFilename, const
std::string& strContents)
{
std::ofstream ofs(strFilename.c_str());
ofs << strContents;

}

int main()
{
string strBuf;
string strFileName("info.dat");
int iRet = ReadFileToString(strFileName,strBuf);
if(iRet == true)
WriteStringToFile("info1.dat",strBuf);

}

they work fine!


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.