mql4 - How to read .txt file into mql variable - readfile

variable.txt file :
10;20;30;40;50
how to import the variable.txt into mql4 variable
a=10
b=20
c=30
d=40
e=50
thank you

This does not reproduce the lettering indicated in your suggested output, but is perhaps a more useful example in general:
ResetLastError();
int next_int = 0;
int filehandle = FileOpen("variable.txt",FILE_READ|FILE_CSV|FILE_ANSI);
if( filehandle != INVALID_HANDLE ) {
while(!FileIsLineEnding(file_handle) && !FileIsEnding(file_handle)) {
next_int = StringToInteger(FileReadString(filehandle));
Print("the next int is ",next_int);
} // while
FileClose(filehandle);
} // if
else {
Print("FileOpen('variable.txt') failed, error= ",GetLastError());
} // else
Review the MQL4 documentation for FileOpen(), FileIsLineEnding() and FileReadString() for more clarity.
Note the opened file path is relative to the MetaTrader4 Terminal path, as described in doc for FileOpen().

Related

Why does this exception appears when reading a file, but not when storing in it?

I'm currently working on a project with MFC and I noticed something weird that apparently has been there for a couple of years. When I launch the .exe of the program, it will do n number of things including reading a .DAT file and storing it as well. If the file doesn't exists, the program will try to find it with no luck throwing this CFile exception: The file could not be located. Which is correct because it doesn't exists. I have to do some operations first to generate that file, the storing process works fine. When the file exists and I run the program again, it's supposed read the file but this CArchive exception shows up: Invalid file format. And I don't understand why.
This is the Serialize():
//Fruits.cpp
void CFruits::Serialize(CArchive &ar)
{
int nVersion = 0;
CObject::Serialize(ar);
ar.SerializeClass(GetRuntimeClass());
if(ar.IsStoring())
{
ar.Write(&m_bInit,sizeof(bool));
ar.Write(&m_bYummy,sizeof(bool));
ar.Write(&m_bAcid, sizeof(bool));
ar.Write(&m_bFresh,sizeof(bool));
...
...
...
ar<<m_cType;
ar<<m_cColour;
ar<<m_cFlavor;
ar<<m_cPrice;
ar<<m_cQuantity;
}
else
{
nVersion = ar.GetObjectSchema();
ar.Read(&m_bInit,sizeof(bool));
ar.Read(&m_bYummy,sizeof(bool));
ar.Read(&m_bAcid, sizeof(bool));
ar.Read(&m_bFresh,sizeof(bool));
...
...
...
if( nVersion >= 2 || nVersion < 0)
ar<<m_cType;
else
m_cType=0;
if (nVersion >= 3 || nVersion < 0)
ar<<m_cColour;
else
m_cColour=0;
if (nVersion >= 4 || nVersion < 0)
ar<<m_cFlavor;
else
ar<<m_cFlavor=0;
if( nVersion >= 5 || nVersion < 0)
{
ar<<m_cPrice;
ar<<m_cQuantity;
}
else
{
m_cPrice=0;
m_cQuantity=0;
}
}
m_oSales.Serialize(ar);
m_oAdmin.Serialize(ar);
...
...
}
IMPLEMENT_SERIAL(CVehiculo,CObject,VERSIONABLE_SCHEMA | 6)
This is the SerializeElements:
//Fruits.cpp
void AFXAPI SerializeElements(CArchive &ar,CFruits * fruits,int ncount)
{
try
{
for(cont=0;cont<ncount;cont++)
fruits[cont].Serialize(ar);
}
catch(CArchiveException *AE)
{
//Here it stores the exception in a Log. Exception 5
}
}
The serializeElements is used to store and read the file n times, as declared here in the header file of fruits:
//Fruits.h
class CFruits : public CObject
{
public:
CFruits();
CFruits(const CFruits &O);
virtual ~CFruits();
void operator = (const CFruits &O);
void Serialize(CArchive &ar);
protected:
DECLARE_SERIAL(CFruits)
};
void AFXAPI SerializeElements(CArchive &ar,CFruits * fruits,int ncount);
typedef CArray<CFruits, CFruitso&> TArrayFruits;
The values of this Array, and the methods used to call the serialize are defined here in my main function:
//main.h
#include "CFruits.h"
class CMain : public CDialog
{
// Construction
public:
enum T_Fruits { eFruitsOnLine, eFruitsIng, eFruitsTra, eFruitsAnt, eFruitsP3, eFruitsP2, eFruitsP1, eFruitsC1, eFruitsC0, eFruitsEscape, eFruitsVideo};
private:
void StoreFruits();
void ReadFruits();
The SerializeElements for-loop is supposed to run 11 times, but I noticed that it only does it 1 time, then the Schema version changes to -1, (originally 6 cause I managed to trace the value). This happens only when reading the file.
I've tried the following:
I can't use debug so I have to use Logs, I placed a Log after every sentence in the Serialize() function, I found what seems to be the issue, this line:
ar.SerializeClass(GetRuntimeClass());
I used a try-catch and found that when that sentence happens, it throws the exception so, it doesn't continue reading. That is the moment where the version changes to -1. I tried to change that to:
ar.SerializeClass(RUNTIME_CLASS(CFruits));
Is the same result, I've read many forums trying to find the answer but I can't seem to do so. I've read the documentation and I found this here:
https://learn.microsoft.com/en-us/cpp/mfc/reference/carchive-class?view=vs-2019#serializeclass
Like ReadClass, SerializeClass verifies that the archived class
information is compatible with your runtime class. If it is not
compatible, SerializeClass will throw a CArchiveException.
But it doesn't make sense to me, because it doesn't fail storing. Should I look into something else?
Thank you
EDIT:
I'm posting the Store and Read methods
void CMain::ReadFruits()
{
CString CSerror, sFileName;
CString sDebug;
try
{
sFileName.Format("FRUITS%03d.DAT",GetNumT());
CFile fFruitsTag(sFileName,CFile::modeRead);
CArchive ar(&fFruitsTag,CArchive::load);
m_vFruits.Serialize(ar);
ar.Close();
fFruitsTag.Close();
}
catch(CFileException *FE)
{
...
}
catch(CArchiveException *AE)
{
...
}
}
void CMain::StoreFruits()
{
CString CSerror, sFileName;
try
{
if(!m_bStoringFruits)
{
sFileName.Format("FRUITS%03d.DAT",GetNumT());
m_bStoringFruits=true;
CFile fFruitsTag(sFileName,CFile::modeCreate|CFile::modeWrite);
CArchive ar(&fFruitsTag,CArchive::store);
m_vFruits.Serialize(ar);
ar.Close();
fFruitsTag.Close();
m_bStoringFruits=false;
}
}
catch(CFileException *FE)
{
...
}
catch(CArchiveException *AE)
{
...
}
catch(CException *e)
{
...
}
}

ifstream - monitor updates to file

I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.

catch error from blank xml file

I am using C++ and I read in and parse an XML file. If the file does not exist it gets created and if it does exist and has correctly formatted data in it there no errors. My problem is when I try to read in a blank XML file (completely blank not even the header) my program crashes as it tries to process the data from the XML file. I need to be able to catch the error before that happen so I can wright the correct settings back to the file or remove the file and make a new one. Is there a way to do this such as checking to see if a node is NULL? And how would I do it?
class XmlDomErrorHandler : public HandlerBase
{
public:
void fatalError(const SAXParseException &exc) {
printf("Fatal parsing error at line %d\n", (int)exc.getLineNumber());
exit(-1);
}
};
void XmlParentNode::refreshAllNodes()
{
m_children.clear();
m_childrernByName.clear();
for(int j =0; j < getInnerParentNode()->getChildNodes()->getLength(); ++j) //crashes here on first pass if xmlfile is empty
{
//code that is never reached
}
XmlDocument::XmlDocument(String name):
XmlParentNode(),
m_pOwner(NULL)
{
if(XmlManager::Get()->initialize())
{
XMLCh* xmlName = XMLString::transcode(StringA(name));
setInnerNode(XmlManager::Get()->getDOMImplementation()->createDocument(NULL, xmlName , NULL));
XMLString::release(&xmlName);
}
}
XmlDocument::XmlDocument(FilePath path):
XmlParentNode(),
m_pOwner(NULL)
{
XMLCh* xmlPath = XMLString::transcode(StringA(path.ToString()));
XercesDOMParser* parser = new XercesDOMParser();
parser->parse(xmlPath);
if(!parser)
{
ErrorHandler* errorHandler = (ErrorHandler*) new XmlDomErrorHandler();
parser->setErrorHandler(errorHandler);
}
DOMDocument* p_Doc= parser->getDocument();
m_pOwner = parser;
XMLString::release(&xmlPath);
if (p_Doc!= NULL)
{
setInnerNode(p_Doc);
refreshAllNodes();
}
}
Sadly I can't stop people for editing the XML file as users need access to it so they can edit settings.
I am new to XML so maybe I'm missing something easy.
I have been using XML Parsing with DOM and a guide I found here
I solved the problem.
I added a check before the for loop that crashed.
if(getInnerParentNode() && getInnerParentNode()->getChildNodes())
{
for(int j =0; j < getInnerParentNode()->getChildNodes()->getLength(); ++j) //was crashing here on first pass if xmlfile is empty
{
//code that was not being reached
}
}

replace some value in text line in c++

Hi guys i use this code to find the line included seta r_fullscreen "0" and if the value for this line is 0 return MessageBox but my question is if the value of seta r_fullscreenis "0" so how i can replace this value to "1" in this line ?
ifstream cfgm2("players\\config_m2.cfg",ios::in);
string cfgLine;
Process32First(proc_Snap , &pe32);
do{
while (getline(cfgm2,cfgLine)) {
if (string::npos != cfgLine.find("seta r_fullscreen")){
if (cfgLine.at(19) == '0'){
MessageBox(NULL,"run in full Screen mod.","ERROR", MB_OK | MB_ICONERROR);
...
You can use std::string::find() and std::string::replace() to do this. After you have located the line containing the configuration specifier seta r_fullscreen you can do something like the following.
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
cfgLine.replace(pos, 3, "\"1\"");
}
You should not assume that the configuration value "0" is at a specific offset as there may be additional spaces between r_fullscreen and "0".
After seeing your additional comments you need to update the configuration file after the changes have been made. The changes you make to the string only apply to the copy in memory and are not automatically saved to the file. You will need to save each line after it has been loaded and changed and then save the updates out to the file. You should also move the process of updating the config file outside of do/while loop. If yo don't you will read/update the file for each process you check.
The example below should get you started.
#include <fstream>
#include <string>
#include <vector>
std::ifstream cfgm2("players\\config_m2.cfg", std::ios::in);
if(cfgm2.is_open())
{
std::string cfgLine;
bool changed = false;
std::vector<std::string> cfgContents;
while (std::getline(cfgm2,cfgLine))
{
// Check if this is a line that can be changed
if (std::string::npos != cfgLine.find("seta r_fullscreen"))
{
// Find the value we want to change
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
// We found it, not let's change it and set a flag indicating the
// configuration needs to be saved back out.
cfgLine.replace(pos, 3, "\"1\"");
changed = true;
}
}
// Save the line for later.
cfgContents.push_back(cfgLine);
}
cfgm2.close();
if(changed == true)
{
// In the real world this would be saved to a temporary and the
// original replaced once saving has successfully completed. That
// step is omitted for simplicity of example.
std::ofstream outCfg("players\\config_m2.cfg", std::ios::out);
if(outCfg.is_open())
{
// iterate through every line we have saved in the vector and save it
for(auto it = cfgContents.begin();
it != cfgContents.end();
++it)
{
outCfg << *it << std::endl;
}
}
}
}
// Rest of your code
Process32First(proc_Snap , &pe32);
do {
// some loop doing something I don't even want to know about
} while ( /*...*/ );

Partial line from cpp file ending up in output file - haunted code?

I'm sorry, it would be extremely difficult to make a fully reproducible version of the error --- so please bare with my schematic code.
This program retrieves information from a web page, processes it, and saves output to an ASCII file. I also have a 'log' file (FILE *theLog---contained within a Manager object) for reporting errors, etc.
Some background methods:
// Prints string to log file
void Manager::logEntry(const string lstr) {
if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}
// Checks if file with given name already exists
bool fileExists(const string fname) {
FILE *temp;
if( temp = fopen(fname.c_str(), "r") ) {
fclose(temp);
return true;
} else { return false; }
}
// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
if(oFile = fopen(fname.c_str(), "w") ) { return true; }
else { return false; }
}
The stuff causing trouble:
// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
// stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
char logStr[CHARLIMIT_LARGE]; // CHARLIMIT_LARGE = 2048
sprintf(logStr, "Saving Data...\n");
man->logEntry( string(logStr) ); // This appears fine in 'theLog' correctly
string data = stu->getDataPrefixStr() + getDataFromURL() + "\n"; // fills 'data' with stuff
data += stu->getDataSuffixStr();
if( fileExists(dataFileName) ) {
sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
man->logEntry( string(logStr) );
if( foreCon == -1 ) {
sprintf(logStr, "foreCon = %d, ... exiting.", foreCon); // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
tCase->logEntry( string(logStr) );
return false;
} else {
sprintf(logStr, "foreCon = %d, overwriting file.", foreCon); // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
tCase->logEntry( string(logStr) );
}
}
// Initialize output file
FILE *outFile;
if( !initFile(outFile, dataFileName) ) {
sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return false;
}
fprintf(outFile, "%s", data.c_str()); // print data to output file
if( fclose(outFile) != EOF) {
sprintf(logStr, "saved to '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return true;
}
return false;
}
If the file already exists, AND 'int foreCon = -1' then the code should print out line 'A' to the logFile. If the file exists and foreCon != -1, the old file is overwritten with data. If the file doesn't exist, it is created, and the data is written to it.
The result however, is that a broken up version of line 'A' appears in the data file AND line 'B' is printed in the log file!!!!
What the data file looks like:
.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
The second line and onward look correct, but there is an extra line that contains part of line 'A'.
Now, the REALLY WEIRD PART. If I comment out everything in the if( foreCon == -1) { ... } block, then the data file looks like:
%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
There is still an extra line, but it is the LITERAL CODE copied into the data file.
I think there is a poltergeist in my code. I don't understand how any of this could happen.
Edit: I've tried printing to console the data string, and it gives the same messed up values: i.e. %d, ... exiting.20130127 161456 - so it must be something about the string instead of the FILE *
Answer based on your latest comment:
getDataPrefixStr() ends up returning a string which starts with
something like string retStr = COMCHAR + " file created on ..."; such
that const char COMCHAR = '#';. Could the COMCHAR be the problem??
You can't add characters and string literals (which are arrays of char, not strings) like that.
You're adding 35 (the ASCII for "#") to the address of " file created on ... ", i.e. getDataPrefixStr() is whatever starts 35 characters from the start of that string. Since all literal strings are stored together in the same data area, you'll get strings from the program in the output.
Instead, you cold do
const string COMCHAR = "*";
string retStr = COMCHAR + " file created on ...";
It could be that logStr is too short and that it is causing data to be overwritten in other buffers (did you double check CHARLIMIT_LARGE?). You can diagnose this by commenting all writes to logStr (sprintf) and see if data is still corrupted. In general, your code is vulnerable to this if a user can set dataFileName (to be a very long string); use snprintf or ostringstream instead.
Otherwise, I would guess that either stu->getDataPrefixStr() or getDataFromURL() are returning corrupted results or return type char* instead of string. Try printing these values to the console directly to see if they are corrupted or not. If they return a char*, then data = stu->getDataPrefixStr() + getDataFromURL() will have undefined behavior.
if( temp = fopen(fname.c_str(), 'r') ) {
should be
if( temp = fopen(fname.c_str(), "r") ) {