I want to read a whole file into a string. I am using Embarcadero C++Builder XE.
When I use the below code in my project, it is giving errors:
#include <iostream>
#include <iomanip>
#include <iterator>
#include <fstream>
std::ifstream in(Path);
std::string s((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
[ILINK32 Error] Error: Unresolved external 'std::_Mutex::_Lock()' [ILINK32 Error] Error: Unresolved external 'std::_Mutex::_Unlock()' [ILINK32 Error] Error: Unresolved external 'std::char_traits::eq_int_type(const int&, const int&)' [ILINK32 Error] Error: Unresolved external 'std::char_traits::not_eof(const int&)' [ILINK32 Error] Error: Unresolved external 'std::char_traits::to_char_type(const int&)' [ILINK32 Error] Error: Unresolved external 'std::char_traits::eof()' [ILINK32 Error] Error: Unresolved external 'std::char_traits::to_int_type(const char&)' [ILINK32 Error] Error: Unresolved external 'std::locale::id::operator unsigned int()' [ILINK32 Error] Error: Unresolved external 'std::locale::name() const' [ILINK32 Error] Error: Unresolved external 'std::codecvt_base::codecvt_base(unsigned int)' [ILINK32 Error] Error: Unresolved external 'std::locale::facet::_Incref()' [ILINK32 Error] Error: Unresolved external 'std::ios_base::ios_base()' [ILINK32 Error] Error: Unresolved external 'std::ios_base::getloc() const' [ILINK32 Error] Error: Unresolved external 'std::ctype::_Getcat(std::locale::facet * *, std::locale *)' [ILINK32 Error] Error: Unresolved external 'std::ctype::widen(char) const' [ILINK32 Error] Error: Unresolved external 'std::ios_base::rdstate() const' [ILINK32 Error] Error: Unable to perform link
Any other solutions for reading a file into a string?
Lets create an empty VCL Form app and add a single TMemo
control on it. The IDE will name it Memo1
automatically . The Memo object is a Text editor with 2 important properties:
Memo1->Text
Text
is a System::String
(automatically reallocable string class from VCL holding the whole text of the memo. String
has a Length()
function returning number of characters present, and each character is accessed using the []
operator like this (indexed from 1 !!!):
String s = _D("123456"); // set some string to s
int l = s.Length(); // get its length
for (int i = 1; i <= l; i++) s[i] = '0'; // change all the chars to zeros
Memo1->Text = s; // feed it to Memo
There are tons of support functions inside String
, the most important for you is formatted output:
Memo1->Text = String().sprintf(_D("float number: %7.3f"), float(123.456));
You can use String
as your local variables, too:
String s = _D("some text");
Memo1->Text = s;
Also for backward compatibility, if you need a char*
for some functions, then just assign the String
to an AnsiString
and call its c_str()
method:
String s = _D("some text");
AnsiString as = s;
char *txt = as.c_str();
But beware not to overwrite unallocated space, or use that pointer after any reallocation inside as
, or after as
goes out of scope. This is used mainly as input parameter for Win32 API functions, C functions, non-VCL LIBs/DLLs, etc.
Memo1->Lines
This is a TStrings
class, which holds a dynamic array of String
s. In a TMemo, each element represents a line in the Text
. You can dynamically add lines to Memo1
like this:
Memo1->Lines->Add(_D("text 1"));
Memo1->Lines->Add(_D("text 2"));
Memo1->Lines->Add(_D("text 3"));
You can load/save the whole Memo contents like this:
Memo1->Lines->LoadFromFile("file1.txt");
Memo1->Lines->SaveToFile("file1.txt");
Any change in Memo1->Lines
will also change Memo1->Text
, and vice versa, as they both represent the same thing. You can have your Memo hidden (invisible) and still use it in case you do not want to show what are you doing ...
You can also load an entire file into a char[]
buffer using file access functions without any VCL component, like this:
int hnd = FileOpen("file1.txt", fmOpenRead); // open file hnd>=0 if all OK
int siz = FileSeek(hnd, 2, 0); // point to end of file and return position = file size
FileSeek(hnd, 0, 0); // point back to start of file
char *txt = new char[siz+1] // allocate space for text and null terminator
FileRead(hnd, txt, siz); // load the file into memory at once
FileClose(hnd); // close file as we do not need it anymore
txt[siz] = 0; // add null termination just to be safe (text files do not contains zeros usually)
// do your thing with txt[siz]
delete[] txt;
Or:
TFileStream *strm = new TFileStream("file1.txt", fmOpenRead); // open file
int siz = strm->Size; // file size
char *txt = new char[siz+1] // allocate space for text and null terminator
strm->ReadBuffer(txt, siz); // load the file into memory at once
delete strm; // close file as we do not need it anymore
// do your thing with txt[siz]
delete[] txt;
Or:
TMemoryStream *strm = new TMemoryStream;
strm->LoadFromFile("file1.txt"); // open file
// do your thing with strm->Memory up to strm->Size bytes...
delete strm;
Unlike std::fstream
, these will work for any file ... even if holding control codes.