forked from rosh/MQL5Book
123 lines
3.6 KiB
MQL5
123 lines
3.6 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| FileHolder.mqh |
| |||
//| Copyright 2021, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
| |||
#include "MqlError.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Base auxiliry class just to clean up internal error flags, |
| |||
//| which may remain after previous function calls |
| |||
//+------------------------------------------------------------------+
| |||
class FileBase
| |||
{
| |||
protected:
| |||
FileBase()
| |||
{
| |||
ResetLastError();
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Single file-handle guard to prevent resource leak, |
| |||
//| closes file automatically on object deletion |
| |||
//+------------------------------------------------------------------+
| |||
class FileOpener : public FileBase
| |||
{
| |||
public:
| |||
const int handle;
| |||
const string name;
| |||
FileOpener(const string filename, const int flags, const ushort delimiter = '\t', const uint codepage = CP_ACP) :
| |||
handle(FileOpen(filename, flags, delimiter, codepage)), name(filename)
| |||
{
| |||
}
| |||
| |||
~FileOpener()
| |||
{
| |||
ResetLastError();
| |||
FileGetInteger(handle, FILE_SIZE); // marks internal error if handle is incorrect
| |||
if(handle != INVALID_HANDLE)
| |||
{
| |||
if(_LastError == 0)
| |||
{
| |||
#ifdef FILE_DEBUG_PRINT
| |||
Print(__FUNCTION__, ": Automatic close for handle: ", handle);
| |||
#endif
| |||
FileClose(handle);
| |||
}
| |||
else
| |||
{
| |||
PrintFormat("%s: handle %d is incorrect, %s(%d)",
| |||
__FUNCTION__, handle, E2S(_LastError), _LastError);
| |||
}
| |||
}
| |||
}
| |||
};
| |||
| |||
#define CONTEXT_MARK NULL
| |||
#define CLEAR(P) if(CheckPointer(P) == POINTER_DYNAMIC) delete P;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Multiple file-handle guard to prevent resource leak, |
| |||
//| generates FileOpener objects upon requests, then delete them |
| |||
//| automatically on leaving local contexts |
| |||
//+------------------------------------------------------------------+
| |||
class FileHolder
| |||
{
| |||
static FileOpener *files[];
| |||
int expand()
| |||
{
| |||
return ArrayResize(files, ArraySize(files) + 1) - 1;
| |||
}
| |||
public:
| |||
FileHolder()
| |||
{
| |||
const int n = expand();
| |||
if(n > -1)
| |||
{
| |||
files[n] = CONTEXT_MARK;
| |||
}
| |||
}
| |||
| |||
~FileHolder()
| |||
{
| |||
for(int i = ArraySize(files) - 1; i >= 0; --i)
| |||
{
| |||
if(files[i] == CONTEXT_MARK)
| |||
{
| |||
// shrink array and exit
| |||
ArrayResize(files, i);
| |||
return;
| |||
}
| |||
| |||
CLEAR(files[i]);
| |||
}
| |||
}
| |||
| |||
int FileOpen(const string filename, const int flags, const ushort delimiter = '\t', const uint codepage = CP_ACP)
| |||
{
| |||
const int n = expand();
| |||
if(n > -1)
| |||
{
| |||
files[n] = new FileOpener(filename, flags, delimiter, codepage);
| |||
return files[n].handle;
| |||
}
| |||
return INVALID_HANDLE;
| |||
}
| |||
| |||
static string GetFilename(const int h)
| |||
{
| |||
for(int i = 0; i < ArraySize(files); ++i)
| |||
{
| |||
if(files[i] != NULL && files[i].handle == h)
| |||
{
| |||
return files[i].name;
| |||
}
| |||
}
| |||
return NULL;
| |||
}
| |||
};
| |||
| |||
static FileOpener *FileHolder::files[];
| |||
//+------------------------------------------------------------------+
|