172 lines
6.4 KiB
MQL5
172 lines
6.4 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| FileSaveLoad.mq5 |
|
||
|
//| Copyright 2021, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
|
||
|
#define PRT(A) Print(#A, "=", (A))
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Struct for compound field in Simple struct |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct Pair
|
||
|
{
|
||
|
short x, y;
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Example struct: structs with simple fields only are allowed for |
|
||
|
//| functions FileSave/FileLoad; this can't be a class |
|
||
|
//+------------------------------------------------------------------+
|
||
|
struct Simple
|
||
|
{
|
||
|
double d;
|
||
|
int i;
|
||
|
datetime t;
|
||
|
color c;
|
||
|
uchar a[10]; // fixed size array is ok
|
||
|
bool b;
|
||
|
Pair p; // compound fields (nested simple structs) are allowed as well
|
||
|
|
||
|
// string field or dynamic array will cause the following compile error:
|
||
|
// structures or classes containing objects are not allowed
|
||
|
// string s;
|
||
|
// uchar a[];
|
||
|
|
||
|
// pointers are also prohibited for FileSave/FileLoad
|
||
|
// void *ptr;
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Custom equivalent of FileSave function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
template<typename T>
|
||
|
bool MyFileSave(const string name, const T &array[], const int flags = 0)
|
||
|
{
|
||
|
const int h = FileOpen(name, FILE_BIN | FILE_WRITE | flags);
|
||
|
if(h == INVALID_HANDLE) return false;
|
||
|
FileWriteArray(h, array);
|
||
|
FileClose(h);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Custom equivalent of FileLoad function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
template<typename T>
|
||
|
long MyFileLoad(const string name, T &array[], const int flags = 0)
|
||
|
{
|
||
|
const int h = FileOpen(name, FILE_BIN | FILE_READ | flags);
|
||
|
if(h == INVALID_HANDLE) return -1;
|
||
|
const uint n = FileReadArray(h, array, 0, (int)(FileSize(h) / sizeof(T)));
|
||
|
// the next check is our custom improvement over standard FileLoad:
|
||
|
// we show the warning if file size is not a multiple of struct size
|
||
|
const ulong leftover = FileSize(h) - FileTell(h);
|
||
|
if(leftover != 0)
|
||
|
{
|
||
|
PrintFormat("Warning from %s: Some data left unread: %d bytes",
|
||
|
__FUNCTION__, leftover);
|
||
|
SetUserError((ushort)leftover);
|
||
|
}
|
||
|
FileClose(h);
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Output byte array in hex |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void ByteArrayPrint(const uchar &bytes[],
|
||
|
const int row = 16, const string separator = " | ",
|
||
|
const uint start = 0, const uint count = WHOLE_ARRAY)
|
||
|
{
|
||
|
string hex = "";
|
||
|
const int n = (int)MathCeil(MathLog10(ArraySize(bytes) + 1));
|
||
|
for(uint i = start; i < MathMin(start + count, ArraySize(bytes)); ++i)
|
||
|
{
|
||
|
if(i % row == 0 || i == start)
|
||
|
{
|
||
|
if(hex != "") Print(hex);
|
||
|
hex = StringFormat("[%0*d]", n, i) + " ";
|
||
|
}
|
||
|
hex += StringFormat("%02X", bytes[i]) + separator;
|
||
|
}
|
||
|
if(hex != "") Print(hex);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Script program start function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnStart()
|
||
|
{
|
||
|
Simple write[] =
|
||
|
{
|
||
|
{+1.0, -1, D'2021.01.01', clrBlue, {'a'}, true, {1000, 16000}},
|
||
|
{-1.0, -2, D'2021.01.01', clrRed, {'b'}, true, {1000, 16000}},
|
||
|
};
|
||
|
const string filename = "MQL5Book/rawdata";
|
||
|
|
||
|
// PART I. Normal execution
|
||
|
|
||
|
PRT(FileSave(filename, write/*, FILE_COMMON*/)); // true
|
||
|
// PRT(MyFileSave(filename, simple/*, FILE_COMMON*/)); // does the same
|
||
|
|
||
|
Simple read[];
|
||
|
PRT(FileLoad(filename, read/*, FILE_COMMON*/)); // 2
|
||
|
// PRT(MyFileLoad(filename, read/*, FILE_COMMON*/)); // does the same
|
||
|
|
||
|
// make sure that the read data is equal to what has been written
|
||
|
PRT(ArrayCompare(write, read)); // 0
|
||
|
|
||
|
// convert struct array to byte array to show its raw presentation
|
||
|
uchar bytes[];
|
||
|
for(int i = 0; i < ArraySize(read); ++i)
|
||
|
{
|
||
|
uchar temp[];
|
||
|
PRT(StructToCharArray(read[i], temp));
|
||
|
ArrayCopy(bytes, temp, ArraySize(bytes));
|
||
|
}
|
||
|
ByteArrayPrint(bytes);
|
||
|
/*
|
||
|
Output:
|
||
|
|
||
|
[00] 00 | 00 | 00 | 00 | 00 | 00 | F0 | 3F | FF | FF | FF | FF | 00 | 66 | EE | 5F |
|
||
|
[16] 00 | 00 | 00 | 00 | 00 | 00 | FF | 00 | 61 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
|
||
|
[32] 00 | 00 | 01 | E8 | 03 | 80 | 3E | 00 | 00 | 00 | 00 | 00 | 00 | F0 | BF | FE |
|
||
|
[48] FF | FF | FF | 00 | 66 | EE | 5F | 00 | 00 | 00 | 00 | FF | 00 | 00 | 00 | 62 |
|
||
|
[64] 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 01 | E8 | 03 | 80 | 3E |
|
||
|
*/
|
||
|
|
||
|
uchar bytes2[];
|
||
|
// we can read directly in byte array
|
||
|
PRT(FileLoad(filename, bytes2/*, FILE_COMMON*/)); // 78, 39 * 2
|
||
|
PRT(ArrayCompare(bytes, bytes2)); // 0, equality
|
||
|
|
||
|
// PART II. Various problematic stuff
|
||
|
|
||
|
// example of error-free yet incorrect usage:
|
||
|
// the receiving struct type does not correspond to actual stored data
|
||
|
MqlDateTime mdt[];
|
||
|
PRT(sizeof(MqlDateTime)); // 32
|
||
|
// Warning from MyFileLoad<MqlDateTime>: Some data left unread: 14 bytes
|
||
|
PRT(MyFileLoad(filename, mdt)); // 2
|
||
|
ArrayPrint(mdt);
|
||
|
/*
|
||
|
Output is a mess:
|
||
|
|
||
|
[year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
|
||
|
[0] 0 1072693248 -1 1609459200 0 16711680 97 0
|
||
|
[1] -402587648 4096003 0 -20975616 16777215 6286950 -16777216 1644167168
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
// compile error, because type string is not supported here
|
||
|
string texts[];
|
||
|
FileSave("any", texts); // parameter conversion not allowed
|
||
|
*/
|
||
|
|
||
|
double data[];
|
||
|
PRT(FileLoad("any", data)); // -1, no such file
|
||
|
PRT(_LastError); // 5004, ERR_CANNOT_OPEN_FILE
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|