 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Paul Rosen Guest
|
Posted: Fri Nov 18, 2005 12:09 am Post subject: reading entire file to a string |
|
|
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
|
Posted: Fri Nov 18, 2005 10:28 am Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Fri Nov 18, 2005 1:24 pm Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Fri Nov 18, 2005 1:25 pm Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Fri Nov 18, 2005 1:26 pm Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Fri Nov 18, 2005 4:40 pm Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Sat Nov 19, 2005 10:23 am Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Sat Nov 19, 2005 7:27 pm Post subject: Re: reading entire file to a string |
|
|
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
|
Posted: Mon Nov 21, 2005 10:35 am Post subject: Re: reading entire file to a string |
|
|
#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 |
|
 |
|
|
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
|
|