Writing nested arrays to bin file

 

I am using Arrays.mqh listing to write nested arrays to .bin file with _writer.mq5. I think it is working because when compared written nested arrays that are structs, the bin file that is created is not zero bytes in size.

 Now the problem am facing is in trying to read the created bin file. _read.mq5 indicates all the array values as 0.0 which is not what was written.

So my question is how does one read a bin file that has nested arrays? Here are the listings.

 

Arrays.mqh 

//+------------------------------------------------------------------+
//|                                                       Arrays.mqh |
//+------------------------------------------------------------------+
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Carrays
  {
private:

public:
            Carrays        *N[];
            double         n[];
            
            void ~Carrays()
               {
                  int _nest_size=ArraySize(N);
                  for(int i=_nest_size-1;i>=0;i--)
                    {
                        if(CheckPointer(N[i])==POINTER_DYNAMIC)
                          {
                              delete N[i];
                          }
                    }
               }
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Cnest : public Carrays
  {
public:
                     Cnest(int Size)
                        {
                           ArrayResize(N,Size);
                        }
                     ~Cnest(void){};
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class Cnested : public Carrays
  {
public:
                     Cnested(int Size)
                        {
                           ArrayResize(n,Size);
                           ArrayInitialize(n,0.0);
                        }
                     ~Cnested(void){};
  };
//+------------------------------------------------------------------+

 

_write.mq5,

 

//+------------------------------------------------------------------+
//|                                                       _write.mq5 |
//+------------------------------------------------------------------+
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Arrays.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
      Carrays *_arrays;
      _arrays=new Cnest(3);
      //
      _arrays.N[0]=new Cnested(1);
      _arrays.N[1]=new Cnested(2);
      _arrays.N[2]=new Cnested(3);
      //
      _arrays.N[0].n[0]=1.0;
      
      _arrays.N[1].n[0]=10.0;
      _arrays.N[1].n[1]=20.0;
      
      _arrays.N[2].n[0]=100.0;
      _arrays.N[2].n[1]=200.0;
      _arrays.N[2].n[2]=300.0;
      //
      ResetLastError();
      int _handle=FileOpen("arrays\\demo.bin",FILE_READ|FILE_WRITE|FILE_BIN|FILE_COMMON);
      if(_handle!=INVALID_HANDLE)
         {
            FileSeek(_handle,0,SEEK_END);
            FileWriteArray(_handle,_arrays.N,0,WHOLE_ARRAY);
            FileClose(_handle);
         }
      else
         {
            printf(__FUNCSIG__+" failed to open the file handle: arrays\\demo.bin, err# ",GetLastError());
         }
   
  }
//+------------------------------------------------------------------+

 

and finally _read.mq5

//+------------------------------------------------------------------+
//|                                                        _read.mq5 |
//+------------------------------------------------------------------+
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Arrays.mqh>
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
      Carrays *_arrays;
      _arrays=new Cnest(3);
      //
      _arrays.N=new Cnest(3);
      //
      _arrays.N[0]=new Cnested(1);
      _arrays.N[1]=new Cnested(2);
      _arrays.N[2]=new Cnested(3);
      //
      ArrayResize(_arrays.N[0].n,1);ArrayInitialize(_arrays.N[0].n,0.0);
      ArrayResize(_arrays.N[1].n,2);ArrayInitialize(_arrays.N[1].n,0.0);
      ArrayResize(_arrays.N[2].n,3);ArrayInitialize(_arrays.N[2].n,0.0);
      //
      ResetLastError();
      int _handle=FileOpen("arrays\\demo.bin",FILE_READ|FILE_BIN|FILE_COMMON);
      if(_handle!=INVALID_HANDLE)
         {
            //
            printf(__FUNCSIG__+" handle valid, reading values. ");
            //
            uint _read_size=FileReadArray(_handle,_arrays.N);
            //
            printf(__FUNCSIG__+" READ size : "+IntegerToString(_read_size)+" NEST size : "+IntegerToString(ArraySize(_arrays.N)));
            //
            printf(__FUNCSIG__+" 0,0 : "+DoubleToString(_arrays.N[0].n[0]));
            printf(__FUNCSIG__+" 1,0 : "+DoubleToString(_arrays.N[1].n[0]));
            printf(__FUNCSIG__+" 1,1 : "+DoubleToString(_arrays.N[1].n[1]));
            printf(__FUNCSIG__+" 2,0 : "+DoubleToString(_arrays.N[2].n[0]));
            printf(__FUNCSIG__+" 2,1 : "+DoubleToString(_arrays.N[2].n[1]));
            printf(__FUNCSIG__+" 2,2 : "+DoubleToString(_arrays.N[2].n[2]));
         }
      else
         {
            Print(__FUNCSIG__+" failed to open the file handle: arrays\\demo.bin, err# ",GetLastError());
         }
   
  }
//+------------------------------------------------------------------+
 

You just write the array of pointers :

            FileWriteArray(_handle,_arrays.N,0,WHOLE_ARRAY);
and you are expecting it will write all values, why ?
 
Alain Verleyen:

You just write the array of pointers :

and you are expecting it will write all values, why ?
Hey thanks for the reply. You are probably right. Is there a way to write nested arrays as a single bin file? Are you familiar with serialization?
 

I do not think that it is possible to use FileWriteArray() and FileReadArray() to work with multidimensional arrays in a single file (especially the read part). You may try to save and load the information similar to the way the standard library does it with string and arrays. First, it writes/loads the size of the data that need to be written/loaded, then starts writing/loading the actual items one by one until the size of the data is reached.

From Arrays\ArrayDouble.mqh:

//+------------------------------------------------------------------+
//| Writing array to file                                            |
//+------------------------------------------------------------------+
bool CArrayDouble::Save(const int file_handle)
  {
   int i=0;
//--- check
   if(!CArray::Save(file_handle))
      return(false);
//--- write array length
   if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
      return(false);
//--- write array
   for(i=0;i<m_data_total;i++)
      if(FileWriteDouble(file_handle,m_data[i])!=sizeof(double))
         break;
//--- result
   return(i==m_data_total);
  }
//+------------------------------------------------------------------+
//| Reading array from file                                          |
//+------------------------------------------------------------------+
bool CArrayDouble::Load(const int file_handle)
  {
   int i=0,num;
//--- check
   if(!CArray::Load(file_handle))
      return(false);
//--- read array length
   num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
   Clear();
   if(num!=0)
     {
      if(!Reserve(num))
         return(false);
      for(i=0;i<num;i++)
        {
         m_data[i]=FileReadDouble(file_handle);
         m_data_total++;
         if(FileIsEnding(file_handle))
            break;
        }
     }
   m_sort_mode=-1;
//--- result
   return(m_data_total==num);
  }

I think an easier alternative would be to use CArrayDouble to store your arrays/values. For nested arrays, you may store each CArrayDouble instance on CArrayObj. So it should be CArrayDouble for the deepest levels, and CArrayObj for the rest. After this, you can call the Save() and Load() functions of the class, without having to write a custom solution. You call the save/load function of the main object instance that stores all the others, and the saving and loading will be done recursively.

 
Enrico Lambino:

I do not think that it is possible to use FileWriteArray() and FileReadArray() to work with multidimensional arrays in a single file (especially the read part). You may try to save and load the information similar to the way the standard library does it with string and arrays. First, it writes/loads the size of the data that need to be written/loaded, then starts writing/loading the actual items one by one until the size of the data is reached.

From Arrays\ArrayDouble.mqh:

I think an easier alternative would be to use CArrayDouble to store your arrays/values. For nested arrays, you may store each CArrayDouble instance on CArrayObj. So it should be CArrayDouble for the deepest levels, and CArrayObj for the rest. After this, you can call the Save() and Load() functions of the class, without having to write a custom solution. You call the save/load function of the main object instance that stores all the others, and the saving and loading will be done recursively.

Thanks for the reply. I am exploring an option that does not require OOP. But thanks any way.
Reason: