FileWrite without overwite and remote location

 

Hello,


I'm trying to write CSV files outside of the mt4/experts/files folder. This works. Now I'm trying to do add info to CSV files without overwriting previous info. This doesn't seem to work.

I'm not sure if the FileLenght and BytesWritten part is needed (I don't know what they do?) . 

Basically I need this:

-Check if the CSV file exists. If yes open and go to last line and add the info there. If it doesn't exist yet, make it and go to last line (which is 0 at a new file) and add the info there.

Thanks!

FileName = "TEST.csv";  
         int hFile = CreateFileA(FileName,GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,0,0);    
         string InfoToWrite = "Test123"
         int StringLength = StringLen(InfoToWrite);
         int BytesWritten[]={0};    
         WriteFile(hFile,Buffer,StringLength,BytesWritten,0); 
         CloseHandle(hFile);
 

"This doesn't seem to work." - What exactly is not working?

Please post all your three import statements: CreateFileA(), WriteFile() and Closehandle(). Probably the error is there. And I don't see a declaration of your variable "Buffer". Your 2nd last line should be

WriteFile(hFile, InfoToWrite, StringLength, BytesWritten, 0);

FileLength (nNumberOfBytesToWrite) is needed because the function needs to know how many bytes to write, starting from the pointer lpBuffer.

BytesWritten (pNumberOfBytesWritten) is needed because *you* want to know how many bytes have been written. This can differ from nNumberOfBytesToWrite under some circumstances. In fact, it's the same value the MQL function FileWrite() returns.

 

Hi Paulepanke,

Let me start with posting the whole mql4 file that I'm currently working in.


Then, this does create a file and I was hoping to find the three strings in it. But I only see the last string ("Entry3"). I guess at every new entry it erases any previous data (if any exists). Does this have to do with lpBuffer and/or pNumberOfBytesWritten ? I think I have to make it start at a new line. Don't know how though.

#import "kernel32.dll"
#define GENERIC_READ    0x80000000
#define GENERIC_WRITE   0x40000000
#define FILE_SHARE_READ                 0x00000001
#define FILE_SHARE_WRITE                0x00000002
#define FILE_SHARE_DELETE               0x00000004
#define CREATE_NEW      1
#define CREATE_ALWAYS   2
#define OPEN_EXISTING   3
#define OPEN_ALWAYS     4
#define INVALID_HANDLE -1

int CreateFileA(
      string   FileName,
      int      DesiredAccess,
      int      dwShareMode,
      int      lpSecurityAttributes,
      int      dwCreationDistribution,
      int      dwFlagsAndAttributes,
      int      hTemplateFile
);   
                    
bool WriteFile(
      int      hFile,
      string   Buffer,
      int      nNumberOfBytesToWrite,
      int     lpNumberOfBytesWritten[],
      int      lpOverlapped
);         
   
bool CloseHandle(
      int   hObject
);

int init()
  {

   return(0);
  }
int deinit()
  {
  
   return(0);
  }
int start()
  {
  WriteNewData("Entry1");
  WriteNewData("Entry2");
  WriteNewData("Entry3");
  
   return(0);
  }
  
void WriteNewData(string NewMessage){
   string Location = "C:/test.CSV";  
   int hFile = CreateFileA(Location,GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,0,0);           
   int FileLength = StringLen(NewMessage); 
   int BytesWritten[]={0};    
   WriteFile(hFile,NewMessage,FileLength,BytesWritten,0); 
   CloseHandle(hFile);
}


 
You don't seek to the end of the file, so each write overwrites.
 

Right, now it does. And everything at a new line. Is there a better way to make it automatically open a new line for a new string of text being added?


#import "kernel32.dll"
#define GENERIC_READ    0x80000000
#define GENERIC_WRITE   0x40000000
#define FILE_SHARE_READ                 0x00000001
#define FILE_SHARE_WRITE                0x00000002
#define FILE_SHARE_DELETE               0x00000004
#define CREATE_NEW      1
#define CREATE_ALWAYS   2
#define OPEN_EXISTING   3
#define OPEN_ALWAYS     4
#define INVALID_HANDLE -1

int CreateFileA(
      string   FileName,
      int      DesiredAccess,
      int      dwShareMode,
      int      lpSecurityAttributes,
      int      dwCreationDistribution,
      int      dwFlagsAndAttributes,
      int      hTemplateFile
);   
                    
bool WriteFile(
      int      hFile,
      string   Buffer,
      int      nNumberOfBytesToWrite,
      int     lpNumberOfBytesWritten[],
      int      lpOverlapped
);         
   
bool CloseHandle(
      int   hObject
);

bool LZSeek(
int hObject,
int Number1,
int Number2
);

int init()
  {
  start();
   return(0);
  }
int deinit()
  {
  
   return(0);
  }
int start()
  {
  WriteNewData("Entry1,");
  WriteNewData("\nEntry2,");
  WriteNewData("\nEntry3,");
  WriteNewData("\nEntry4,");
  WriteNewData("\nEntry5,");
  
   return(0);
  }
  
void WriteNewData(string NewMessage){
   string Location = "C:/test.CSV";  
   int hFile = CreateFileA(Location,GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,0,0);           
   int FileLength = StringLen(NewMessage); 
   int BytesWritten[]={0};    
   LZSeek(hFile,0,2);
   WriteFile(hFile,NewMessage,FileLength,BytesWritten,0); 
   CloseHandle(hFile);
}
 

_llseek(handle,0,2) will set the pointer at the end of the file.

What's wrong with the way you write text? A line of code for each line of text? I normally do this:

string text = "hello"
int handle = CollectorOpenFile("C:\\mt4\\file.csv");

for(int i=0; i<blahblah; i++)
{
WriteFile(handle,text+"\n");
}
CloseFile(handle);

 

 

 The extra new line at the end of the file has never caused me any problems.

 

I'm no expert is that the right way to import the functions? Why are CreateFileA etc. outside the import tages?  Mine (which I copy and pasted from another) looks like this:

// constants for function _lopen
#define OF_READ               0
#define OF_WRITE              1
#define OF_READWRITE          2
#define OF_SHARE_COMPAT       3
#define OF_SHARE_DENY_NONE    4
#define OF_SHARE_DENY_READ    5
#define OF_SHARE_DENY_WRITE   6
#define OF_SHARE_EXCLUSIVE    7
 
#import "kernel32.dll"
   int _lopen  (string path, int of);
   int _lcreat (string path, int attrib);
   int _llseek (int handle, int offset, int origin);
   int _lread  (int handle, string buffer, int bytes);
   int _lwrite (int handle, string buffer, int bytes);
   int _lclose (int handle);
   int CreateDirectoryA(string path, int atrr[]);
   bool DeleteFileA(string lpFileName);
   void OutputDebugStringA(string msg);
#import

 

 

 

and then the open, close, write  and create folders functions look like this (maybe modified to my purpose, I can't remember):

//+------------------------------------------------------------------+
//|  open file                     
//+------------------------------------------------------------------+
int CollectorOpenFile (string path)
   {
   int result;
   int handle = _lopen(path,OF_WRITE);
   if(handle<0) //if couldn't open (no file / file already open)
      {
      handle = _lcreat(path,0);
      if(handle<0) //if couldn't create file -> create path
         {
         if(!CreateFullPath(path)) //if couldn't create path -> report big problem
            {
            Alert("1bidask_collector: Failed creating folders: ",path,"  exiting START. (is file already open??)");
            return(-1);
            }
         handle = _lcreat(path,0); //if could create path -> create file
         }//end if(couldn't create file)
        result = _lclose(handle);
        handle = -1;
      }//end if(couldn't initially open file)
      if(handle < 0) //if couldn't initially open file
         {
         handle = _lopen(path,OF_WRITE); 
         result = _llseek(handle,0,0);//pointer at start
         if(result<0)
            {
            return(-1);
            }
         }
   return(handle);
   }
   
   
//+------------------------------------------------------------------+
//|  close file                     
//+------------------------------------------------------------------+
bool CloseFile(int &handle)
   {
   int result=_lclose(handle);
   if(result<0)
      {
      Alert("error closing file with handle:",handle,",  exiting CollectorCloseFile...");
      return(FALSE);
      }
   handle = -1;
   return(TRUE);
   }


//+------------------------------------------------------------------+
//|  write to file
//+------------------------------------------------------------------+
bool WriteFile(int handle, string buffer) 
   {
   int result = _llseek(handle,0,2);//pointer at end
   if(result<0)
      {
      Alert("1bidask_collector: (in CollectorWriteFile) Error placing the pointer to end of file,   exiting WriteFile...");
      return(FALSE);
      }
   int count = StringLen(buffer);
   if(count<1)
      {
      Alert("1bidask_collector: (in CollectorWriteFile) buffer size was:",count,",   exiting WriteFile...");
      return(FALSE);
      }
   result = _lwrite(handle,buffer,count);
   if(result<0)
      {
      Alert("1bidask_collector: error writing to file handle",handle,"  buffer sizë:",count," bytes,   exiting WriteFile...");
      return(FALSE);
      }
   return(TRUE);        
   }


//+------------------------------------------------------------------+
//|  parse path: help make folders
//+------------------------------------------------------------------+
bool ParsePath(string & folder[], string path)
   {
   bool res = false;
   int k = StringLen(path);
   if (k==0) return(res);
   k--;
 
   Print("Parse path=>", path);
   int folderNumber = 0;
//----
   int i = 0;
   while ( k >= 0 )
      {
      int char = StringGetChar(path, k);
      if ( char == 92) //  back slash "\"
         {
         if (StringGetChar(path, k-1)!= 92)
            {
            folderNumber++;
            ArrayResize(folder,folderNumber);
            folder[folderNumber-1] = StringSubstr(path,0,k);
            Print(folderNumber,":",folder[folderNumber-1]);
            }
         else break;         
         }
      k--;   
      }
   if (folderNumber>0) res = true;   
//----
   return(res);   
   }


//+------------------------------------------------------------------+
//|  create all folders
//+------------------------------------------------------------------+
bool CreateFullPath(string path)
   {
   bool res = false;
   if (StringLen(path)==0)
      {
      Alert("1bidask_collector (CreateFullPath): tried ParsePath but length of path was 0");
      return(false);
      }
   Print("Create path=>",path);
//----
   string folders[];
   if (!ParsePath(folders, path))
      {
      Alert("1bidask_collector (CreateFullPath): ParsePath failed");
      return(false);
      }
   Print("Total subfolders:", ArraySize(folders));
   
   int empty[];
   int i = 0;
   while (CreateDirectoryA(folders[i],empty)==0) i++;
   Print("Create folder:",folders[i]);
   i--;
   while (i>=0) 
      {
      CreateDirectoryA(folders[i],empty);
      Print("Created folder:",folders[i]);
      i--;
      }
   if (i<0) res = true;   
//----
   return(res);
   }

 and this works :)

 

Thanks Alladir, I've just inserted it in my code and it does work for me. However, the earlier mentioned code works too, I believe your code is more fail safe.

Now I have another question.


Say that I have 3 csv files File1.csv / File2.csv / File3.csv


The first column indexes the values where the second column gives the actual values. My goal is to match values by index from different files. If for the specific index there is no entry the values from a the nearest previous index should be taken.

For example if I want to match entry 103 then this would be

entry 103 value File1.csv 1986 /  value File2.csv 1565 (entry 102 File2.csv)  / value File3.csv 1752 (entry102 File3.csv)


Is there an option to jump directly to entries?

File1.csv       
100     1029
103     1986
104     1674
105     1029
108     2388
109     2261
112     2448
113     1347
114     1462
116     1641
118     2337
119     1568
122     1894
125     1743
126     1530
127     1510
129     1216
130     1719
133     2099
135     1502

File2.csv       
100     619
102     1565
104     1689
107     2302
110     2287
113     1276
116     1100
119     1996
122     1142
124     1641
127     1764
128     1529
129     2495
132     1239
134     1612
135     2500
136     892
137     798
140     1736
141     2252

File3.csv       
100     1475
102     1753
105     738
108     1798
109     651
110     1512
112     2316
115     1977
117     1975
119     877
120     2042
123     832
124     2024
126     1657
129     1923
130     2193
133     2031
134     2413
137     1965
140     1209
 
Update, the for me obvious solution is to open the files one after the other and go through them until the right entry is found. But this would take rather long if you are working with many big files. That's why I'd prefer to go right away to the right entry.
 
The only way I have ever done this is by scanning in the values of each line and discarding them (or rather, just not using them) until you get to the one you want, then working with it. Some of my indicators use up to 10 files of 3000 lines by 5 columns and it's not slow. It's just reading from disk, no calculations or internet usage.
Reason: