c++c++buildervclc++builder-xe

Getting Error when reading file in string using C++Builder Project


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?


Solution

  • 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:

    1. 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.

    2. Memo1->Lines

      This is a TStrings class, which holds a dynamic array of Strings. 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.