MetaTrader 5 herunterladen

Dateioperationen über WinAPI

28 März 2016, 13:43
MetaQuotes Software Corp.
4
361

Einführung

MQL4 ist in einer Weise entworfen, dass sogar falsch geschriebene Programme nicht in der Lage sind versehentlich Daten von der Festplatte zu löschen. Die verwendeten Funktionen für Datei Lese- und Schreiboperationen können nur in den folgenden Verzeichnissen arbeiten (Zitat):

  • /HISTORY/<aktueller Broker> - insbesondere für die FileOpenHistory Funktion,
  • /EXPERTS/FILES - allgemeiner Fall,
  • /TESTER/FILES - insbesondere für Tests.
Das Arbeiten mit MQL4 Dateien aus anderen Verzeichnissen ist verboten.

Wenn Sie dennoch außerhalb der Verzeichnisse arbeiten müssen (definiert aus Sicherheitsgründen), können Sie die Funktionen des Windows BS (Betriebssystem) aufrufen. Zu diesem Zweck sind die in der kernel32.dll dargestellten API-Funktionen weit verbreitet.



Dateifunktionen der kernel32.dll

Es basiert auf dem in CodeBasse unter File Operations without Limitations - Skript für den MetaTrader 4 gefundenen Skript. Es ist ein gutes Beispiel, wie Funktionen in ein MQL4 Programm importiert werden können

// 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);
#import

Diese Funktionen sind in msdn als veraltet deklariert, aber sie können weiter verwendet werden, siehe Obsolete Windows Programming Elements. Ich werde hier die Beschreibung von Funktionen und Parametern direkt aus diesem Thread nehmen, wie sie von dem Skript-Autor, mandor, beschrieben sind:

// _lopen  : It opens the specified file. It returns: file descriptor.
// _lcreat : It creates the specified file. It returns: file descriptor.
// _llseek : It places the pointer in the open file. It returns: 
// the new shift of the pointer.
// _lread  : It reads the given number of bytes from the open file. 
// It returns: the number of the read bytes; 0 - if it is the end of the file.
// _lwrite : It writes the data from buffer into the specified file. It returns: 
// the number of written bytes.
// _lclose : It closes the specified file. It returns: 0.
// In case of unsuccessfully completion, all functions return the value of 
// HFILE_ERROR=-1.
 
// path   : String that defines the path and the filename.
// of     : The way of opening.
// attrib : 0 - reading or writing; 1 - only reading; 2 - invisible, or 
// 3 - system file.
// handle : File descriptor.
// offset : The number of bytes, by which the pointer shifts.
// origin : It indicates the initial point and the shifting direction: 0 - 
// forward from the beginning; 1 - from the current position; 2 - backward from the end of the file.
// buffer : Receiving/writing buffer.
// bytes  : The number of bytes to read.
 
// Methods of opening (parameter 'of'):
// int OF_READ            =0; // Open file for reading only
// int OF_WRITE           =1; // Open file for writing only
// int OF_READWRITE       =2; // Open file in the read/write mode
// int OF_SHARE_COMPAT    =3; // Open file in the mode of common 
// shared access. In this mode, any process can open this given 
// file any amount of times. At the attempt to open this file in any other
// mode, the function returns HFILE_ERROR.
// int OF_SHARE_DENY_NONE =4; // Open file in the mode of common access 
// without disabling the reading/writing by another process. At the attempt to open 
// this file in the mode of OF_SHARE_COMPAT, the function returns HFILE_ERROR.
// int OF_SHARE_DENY_READ =5; // Open file in the mode of common access with 
// disabling the reading by another process. At the attempt to open this file 
// with the flags of OF_SHARE_COMPAT and/or OF_READ, or OF_READWRITE, the function 
// returns HFILE_ERROR.
// int OF_SHARE_DENY_WRITE=6; // The same, but with disabling the writing.
// int OF_SHARE_EXCLUSIVE =7; // Disable for this current and for all other processes 
// to access to this file in the modes of reading/writing. The file in this mode can be 
// opened only once (with the current process). All other attempts 
// to open the file will fail.


Funktion "Lesen aus Datei"

Betrachten wir die zum Lesen aus einer Datei vorgesehene Funktion. Ihr einziger Parameter ist eine String-Variable, die den Dateinamen enthält. Die importierte Funktion von _lopen(path,0) gibt den Zeiger (Pointer) an die geöffnete Datei zurück und, für ihre Aufgaben, ist sehr ähnlich zu der Funktion FileOpen() in MQL4.

//+------------------------------------------------------------------+
//|   read the file and return a string with its contents            |
//+------------------------------------------------------------------+
string ReadFile (string path) 
  {
    int handle=_lopen (path,OF_READ);           
    if(handle<0) 
      {
        Print("Error opening file ",path); 
        return ("");
      }
    int result=_llseek (handle,0,0);      
    if(result<0) 
      {
        Print("Error placing the pointer" ); 
        return ("");
      }
    string buffer="";
    string char1="x";
    int count=0;
    result=_lread (handle,char1,1);
    while(result>0) 
      {
        buffer=buffer+char1;
        char1="x";
        count++;
        result=_lread (handle,char1,1);
     }
    result=_lclose (handle);              
    if(result<0)  
      Print("Error closing file ",path);
    return (buffer);
  }

Die Funktion _lseek() hat auch ihr Gegenstück in MQL4. Es ist FileSeek(). Die Funktion _lclose wird für das Schließen von Dateien verwendet, wie die Funktion FileClose(). Die einzige neue Funktion ist _lread(Identifikator, Puffer, Bytes), die aus der angegebenen Datei (der Zeiger bei ihr muss vorläufig durch die Funktion _lopen() empfangen werden) ) in die Variable 'buffer' die angegebene Anzahl an Bytes liest. Sie sollten eine String-Konstante mit der benötigten Länge als 'buffer' Variable verwenden. In diesem Beispiel erkennen wir:

    string char1="x";
    result=_lread (handle,char1,1);

- die gegebene String Konstante 'char' hat eine Länge von eins, das heißt, sie erlaubt nur ein Byte in ihr zu lesen. Gleichzeitig spielt der Wert dieser Konstante keine Rolle: es kann beides sein, "x", "Z" und sogar " " (das Leerzeichen). Sie werden nicht in der Lage sein mehr Bytes in ihr zu lesen, als ursprünglich für diese Konstante festgelegt wurde. In diesem Fall, wären die Versuche 2 oder mehr Bytes zu lesen nicht erfolgreich. Außerdem ist das Ergebnis der Funktion _lread() die Anzahl der wirklich gelesenen Bytes. Wenn die Datei 20 Bytes groß ist und Sie versuchen einer 30-Bytes langen Variable mehr als 20 Bytes zu lesen, wird die Funktion 20 zurückgeben. Wenn wir diese Funktion nacheinander anwenden, bewegen wir uns entlang der Datei und lesen einen Block der Dateien nach dem anderen. Zum Beispiel, eine Datei ist 22 Bytes groß. Wir beginnen sie in Blöcken von 10 Bytes zu lesen. Dann, nach zwei Aufrufen der Funktion __lread(handle, buff, 10), bleiben zwei Bytes am Ende der Datei ungelesen.

Bei dem dritten Aufruf wird __lread(handle, buff, 10) will 2 zurückgeben, das heißt, die letzten 2 Bytes werden gelesen. Bei dem vierten Aufruf wird die Funktion einen Nullwert zurückgeben - kein Byte wurde gelesen, der Zeiger ist am Ende der Datei. Es ist diese Tatsache, der die Prozedur des Lesens von Zeichen aus einer Datei in einem Zyklus unterliegt:

    while(result>0) 
      {
        buffer=buffer+char1;
        char1="x";
        count++;
        result=_lread (handle,char1,1);
     }

Solange das Ergebnis (die Anzahl der gelesenen Bytes) mehr als Null ist, wird die Funktion _lread(handle, char1, 1) in Zyklen aufgerufen. Wie Sie sehen, gibt es nichts Kompliziertes in diesen Funktionen. Der Wert des gelesenen Zeichen wird in der Variable mit dem Namen char1 gespeichert. Dieses Zeichen wird von der String Variable 'buffer' bei dem nächsten Durchlauf geschrieben. Nach Abschluss der Operationen, gibt die Funktion ReadFile() die Inhalte der gelesenen Datei in diese Variable zurück. Wie Sie sehen, verursacht es keine Schwierigkeiten.


Funktion "Scheiben in Datei"

Schreiben ist, in gewisser Weise, sogar noch einfacher als Lesen. Sie müssen eine Datei öffnen und in sie hinein ein Array schreiben, mit der Funktion _lwrite (int handle, string buffer, int bytes). Hier ist handle ein durch die Funktion _lopen() erhaltener Datei-Zeiger (Pointer), der Parameter 'buffer' ist eine String-variable, der Parameter 'bytes' zeigt a wie viele Bytes geschrieben werden sollen. Nach dem Schreiben wird die Datei mit der Funktion _lclose() geschlossen. Betrachten wir die Funktion WriteFile() des Autors:

//+------------------------------------------------------------------+
//|  write the buffer contents to the given path                     |
//+------------------------------------------------------------------+
void WriteFile (string path, string buffer) 
  {
    int count=StringLen (buffer); 
    int result;
    int handle=_lopen (path,OF_WRITE);
    if(handle<0) 
      {
        handle=_lcreat (path,0);
        if(handle<0) 
          {
            Print ("Error creating file ",path);
            return;
          }
        result=_lclose (handle);
     }
    handle=_lopen (path,OF_WRITE);               
    if(handle<0) 
      {
        Print("Error opening file ",path); 
        return;
      }
    result=_llseek (handle,0,0);          
    if(result<0) 
      {
        Print("Error placing pointer"); 
        return;
      }
    result=_lwrite (handle,buffer,count); 
    if(result<0)  
        Print("Error writing to file",path,"",count," bytes");
    result=_lclose (handle);              
    if(result<0)  
        Print("Error closing file ",path);
  }

Allerdings sollte wir eine Fehlerüberprüfung durchführen. Zunächst versuchen wir eine Datei zum Schreiben zu öffnen:

    int handle=_lopen (path,OF_WRITE);

(die Function _lopen() wird mit dem Parameter OF_WRITE aufgerufen).

Wenn der Versuch scheitert (handle < 0), versucht sie eine Datei mit dem angegebenen Namen zu erzeugen:

        handle=_lcreat (path,0);

Wenn diese Funktion auch einen negativen Zeiger (Pointer) zurückgibt, wird die Funktion WriteFile() gekürzt. Der restliche Code in dieser Funktion ist ohne weitere Erklärungen verständlich. Die einfachste start() Funktion ermöglicht Ihnen zu überprüfen, wie das Skript File_Read_Write.mq4 funktioniert.

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
    string buffer=ReadFile("C:\\Text.txt");
    int count=StringLen(buffer);
    Print("Bytes counted:",count);
    WriteFile("C:\\Text2.txt",buffer);   
//----
   return(0);
  }
//+------------------------------------------------------------------+

Beachten Sie, dass der Back-Slash ("\") zweimal geschrieben wird, obwohl einmal notwendig ist. Die Sache ist die, dass einige Sonderzeichen, wie das Zeilenvorschub-Zeichen ("\n") oder das Tabulator-Zeichen ("\t") mit Back-Slash geschrieben werde müssen. Wenn Sie dies vergessen, haben Sie eventuell Schwierigkeiten den Pfad in dem Test der Variable während der Programmausführung anzugeben.

Bitte schreiben Sie zwei aufeinander folgende Back-Slashes in der String Konstante, nicht nur einen. Please write two consecutive back slashes in string constant, not only one. In diesem Fall wird der Compiler es zweifelsfrei als richtig akzeptieren..


Alles funktioniert, aber es ist ein Löffel Teer in dem Honigfass: die Skript-Funktion ReadFile() arbeitet bei großen Dateien sehr langsam.

Der Grund für ein derart langsames Lesen der Datei liegt darin, dass wir die die Informationen Byte für Byte lesen (Zeichen). Sie können in der obige Abbildung sehen, dass die Datei mi der Größe von 280.324 Bytes 103 Sekunden benötigt. Das ist die benötigte Zeit, um 280.324 Mal ein Zeichen zu lesen. Sie können die Arbeitszeit unabhängig mit dem an den Artikel angehangenen Skript Read Write.mq4 überprüfen. Wie können wir das Lesen einer Datei beschleunigen? Die Antwort liegt an uns - die Funktion muss, sagen wir 50 Zeichen lesen, nicht einen nach dem Anderen zur geleichen Zeit. Dann wird die Anzahl der _lread() Funktion-Aufrufe 50-Mal reduziert. Daher muss auch das Lesen 50 Mal reduziert werden. Überprüfen wir es.

Neue Funktion zum Lesen Einer Datei in Blöcken je 50 Bytes

Ändern Sie den Code und bennen Sie die neue Version als xFiles,mq4. Kompilieren und starten Sie sie zur Ausführung. Es wird hier daran erinnert, dass Import-Funktionen von DLLs in den Einstellungen (Strg+O) aktiviert sein muss.

Somit beträgt die Ausführungszeit des geänderten Skripts 2047 Millisekunden, was ungefähr 2 Sekunden entspricht. Wir teilen 103 Sekunden (die Ausführungszeit des ursprünglichen Skripts) durch 2 Sekunden und erhalten 103 / 2 = 51,5 Mal. Also hat sich die Programmausführung tatsächlich ungefähr 50 Mal geändert, wie es erwartet wurde. Wie wurde der Code geändert, um dies zu erreichen?

Die Änderungen sind gering:

string ReadFile (string path) 
  {
    int handle=_lopen (path,OF_READ);
    int read_size = 50;           
    string char50="x                                                 ";
 
    if(handle<0) 
      {
        Print("Error opening file ",path); 
        return ("");
      }
    int result=_llseek (handle,0,0);      
    if(result<0) 
      {
        Print("Error placing the pointer" ); 
        return ("");
      }
    string buffer="";
    int count=0;
    int last;
    
    result=_lread (handle,char50,read_size);
    int readen;
    while(result>0 && result == read_size) 
      {
        buffer=buffer + char50;
        count++;
        result=_lread (handle,char50,read_size);
        last = result;
     }
    Print("The last read block has the size of, in bytes:", last);
    char50 = StringSubstr(char50,0,last);
    buffer = buffer + char50;    
    result=_lclose (handle);              
    if(result<0)  
      Print("Error closing file ",path);
    return (buffer);
  }

Bitte beachten Sie, dass die String-Variable 'char50' nun durch die Konstante mit 50 Zeichen (Zeichen "x" und 49 Leerzeichen) initialisiert wird.

Jetzt können wir das Lesen aus einer Datei in einer solchen Weise zum Lesen von 50 Bytes (Zeichen) gleichzeitig in dieser Variable ausführen:

result=_lread (handle,char50,read_size);

Hier: read_size = 50. Natürlich, es ist nicht wahrscheinlich, dass die Größe der zu lesenden Datei immer ein Vielfaches von 50 sein wird, was bedeutet, es wird den Moment geben, in dem der Wert für diese Funktionsausführung ein anderer als 50 sein wird. Das ist ein Signal den Zyklus zu stoppen. Der letzte Block der zu lesenden Zeichen wird in der Variable auf die tatsächliche benötigte Menge an Bytes gekürzt.

Sie können die Größe des Puffers mit der Funktion _lread() auf die Größe von N ändern, aber vergessen Sie nicht zwei Änderungen zu machen:

  1. setzen Sie den Wert von read_size auf 'N';
  2. initialisieren Sie die String-Variable 'char50' der Konstanten Länge von N (N<256).

Nun, wir haben den Lesevorgang beschleunigt. Die letzte verbleibende Aufgabe, ist die Verarbeitung des Fehlers wegen Nicht-existierendem Pfad bei dem Versuch eine Datei zu Schreiben. In der Funktion WriteFile() wurde versucht eine Datei zu erstellen, aber die Situation wurde nicht verarbeitet, weil es keinen Ordner mit dem Pfad zu dem Dateinamen gibt. Also brauchen wir eine weitere Funktion -

Ordner erstellende Funktion

Die Ordner erstellende Funktion ist auch in kernel32.dll verfügbar - CreateDirectory Function. Es sollte hier nur darauf hingewiesen werden, dass diese Funktion nur versucht den untersten Ordner zu erstellen, sie erstellt nicht alle dazwischen liegenden Ordner in dem Pfad, wenn sie nicht vorhanden sind. Zum Beispiel, wenn wir versuchen mit dieser Funktion den Ordner "C:\Ordner_A\Ordner_B" zu erstellen, ist der Versuch nur dann erfolgreich, wenn der Pfad von "C:/Ordner_A" bereits vor dem Funktionsaufruf existiert hat. Andernfalls wird Ordner_B nicht erstellt. Fügen wir dem Import-Abschnitt eine neue Funktion hinzu:

#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[]);
#import

Der erste Parameter enthält den Pfad zum Erstellen eines neuen Ordners, während der zweite Parameter, atrr[], der Bestimmung der Berechtigungen für den zu erstellenden Ordner dient und von dem _SECURITY_ATTRIBUTES Typ sein muss. Wir stellen keine Informationen für den zweiten Parameter bereit, aber übergeben Sie einfach das leere Array mit dem Namen 'int'. In diesem Fall wird der Ordner alle Berechtigungen des übergeordneten Ordners erben. Allerdings, bevor Sie versuchen diese Funktion anzuwenden, müssen wir eine Operation durch führen wie -

Den Pfad Herunter Brechen

In der Tat, erstellen wir einen Ordner der 4. Ebene, zum Beispiel, wie folgt:

"C:\Ordner_A\Ordner_B\Ordner_C\Ordner_D"

Hier rufen wir den Ordner_D auf, einen Ordner der 4. Ebene, weil sich drei Ordnerebenen über ihm befinden. Festplatte 'C:' enthält "Ordner_A", Ordner "C:\Ordner_A\" enthält "Ordner_B", Ordner "C:\Ordner_A\Ordner_B\" enthält "Ordner_C", und so weiter. Das bedeutet, wir müssen den gesamten Pfad zu der Datei in einem Array aus Unterordner herunterbrechen. Nennen wir die notwendige Funktion ParsePath():

//+------------------------------------------------------------------+
//| break apart the path  into an array of subdfolders               |
//+------------------------------------------------------------------+
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);   
   }   
//+------------------------------------------------------------------+

Das Trennzeichen zwischen den Ordnern ist das '\' Zeichen, das den Wert 92 in der ANSI-Kodierung hat. Die Funktion erhält 'path' als ihr Argument und füllt das Array mit dem Namen folder[], übergeben an die Funktion, mit den Namen der gefundenen Pfade, beginnend mit dem niedrigsten und abschließend mit dem obersten. In unserem Beispiel, wird das Array folgende Werte enthalten:

folder[0] = "C:\folder_A\folder_B\folder_C\folder_D";
folder[1] = "C:\folder_A\folder_B\folder_C";
folder[2] = "C:\folder_A\folder_B";
folder[3] = "C:\folder_A";
folder[4] = "C:";

Wenn wir eine Datei mit dem Namen "C:\folder_A\folder_B\folder_C\folder_D\test.txt" schreiben möchten, können wir den angegebenen Pfad in Dateiname test.txt und die Struktur der Unterordner "C:\folder_A\folder_B\folder_C\folder_D" teilen, die diese Datei enthält. Wenn das Programm bei der Erstellung dieser Datei auf diesem Pfad scheitert, sollte zunächst versucht werden einen Ordner auf der untersten Ebene zu erstellen, C:\folder_A\folder_B\folder_C\folder_D".

Wenn auch der Versuch diesen Ordner zu erstellen scheitert, ist höchstwahrscheinlich der übergeordnete Ordner "C:\folder_A\folder_B\folder_C" nicht vorhanden. Also werden wir Ordner von höheren Ebenen erstellen, bis wir die Benachrichtigung über den erfolgreichen Abschluss der Funktion CreateDirectoryA() erhalten. Aus diesem Grund benötigen wir eine Funktion die das String Array 'folder[]' in aufsteigender Reihenfolge mit Ordnernamen ausfüllt. Der erste Null-Index enthält den Ordner der untersten Ebene, das Wurzelverzeichnis befindet sich in dem letzten Array-Index.

Nun können wir die Funktion zusammenstellen, die alle Notwendigen Zwischen-Ordner auf dem angegebenen Pfad erstellt:

//+------------------------------------------------------------------+
//|  It creates all necessary folders and subfolders                 |
//+------------------------------------------------------------------+
bool CreateFullPath(string path)
   {
   bool res = false;
   if (StringLen(path)==0) return(false);
   Print("Create path=>",path);
//----
   string folders[];
   if (!ParsePath(folders, path)) 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);
   }

Nun bleibt nur eine kleine Änderung in der Funktion WriteFile() vorzunehmen, die Möglichkeit einen neuen Ordner zu erstellen berücksichtigend.

//+------------------------------------------------------------------+
//|  write the buffer contents to the given path                     |
//+------------------------------------------------------------------+
void WriteFile (string path, string buffer) 
  {
    int count=StringLen (buffer); 
    int result;
    int handle=_lopen (path,OF_WRITE);
    if(handle<0) 
      {
        handle=_lcreat (path,0);
        if(handle<0) 
          {
            Print ("Error creating file ",path);
            if (!CreateFullPath(path))
               {
               Print("Failed creating folder:",path);
               return;
               }
            else handle=_lcreat (path,0);   
          }
        result=_lclose (handle);
        handle = -1;
     }
    if (handle < 0) handle=_lopen (path,OF_WRITE);               
    if(handle<0) 
      {
        Print("Error opening file ",path); 
        return;
      }
    result=_llseek (handle,0,0);          
    if(result<0) 
      {
        Print("Error placing the pointer"); 
        return;
      }
    result=_lwrite (handle,buffer,count); 
    if(result<0)  
        Print("Error writing to file ",path,"",count," bytes");
    result=_lclose (handle);              
    if(result<0)  
        Print("Error closing file",path);
    return;        
  }

Die Logik, nach der die modifizierte Funktion arbeitet, ist in der folgenden Abbildung angegeben.

Bitte beachten Sie, dass nachdem die neu erstellte Datei geschlossen wurde, setzen wir die Dateideskriptor Variable 'handle' auf einen negativen Wert.

        result=_lclose (handle);
        handle = -1;

Dies wird gemacht, um den Wert von 'value' eine Zeile darunter zu prüfen und die Datei nur mit Leseberechtigung zu öffnen, wenn das erste Öffnen fehlgeschlagen ist.


    if (handle < 0) handle=_lopen (path,OF_WRITE);

Das ermöglicht uns Situationen zu vermeiden, in denen mehrere Dateien versehentlich geöffnet werden und ohne geschlossen zu werden zurückbleiben. In solchen Fällen, informiert das Betriebssystem über das Überschreiten der maximal zulässigen geöffneten Dateien und erlaubt nicht neue Dateien zu öffnen.

Modifizieren wir die Funktion start() um die neuen Funktionen zu testen:

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
    int start = GetTickCount();
    string buffer=ReadFile("C:\\Text.txt");
 
    int middle = GetTickCount();
    int count=StringLen(buffer);
 
    Print("Bytes read:",count);
 
    WriteFile("C:\\folder_A\\folder_B\\folder_C\\folder_D\\Text2.txt",buffer);   
    int finish = GetTickCount();
    Print("File size is ",count," bytes. Reading:",(middle-start)," ms. Writing:",(finish-middle)," ms.");
//----
   return(0);
  }
//+------------------------------------------------------------------+

und starten das Skript xFiles.mq4 zur Ausführung.



Fazit

Es ist nicht sehr schwierig die Funktionen von WinAPI zu verwenden, aber sie sollten auch die Gegenseite bedenken, das Verlassen der "Sandbox":

Vor dem Starten einer unbekannten ausführbaren Anwendung mit der Erweiterung ex4 (ohne MQL4 Quellcode), die den Import von Funktionen externer DLLs erfordern, denken Sie bitte über mögliche Konsequenzen nach.


Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/1540

Beigefügte Dateien |
xFiles.mq4 (8.59 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (4)
Otto Pauser
Otto Pauser | 24 Mai 2017 in 19:22

Und warum funktioniert der Code im MT5 nicht ?

Carl Schreiber
Carl Schreiber | 24 Mai 2017 in 20:39
Otto Pauser:

Und warum funktioniert der Code im MT5 nicht ?

Der original Artikel wurde am 3 июля 2008, 13:44 veröffentlicht. Es gibt andere (google) Beispiele die gehen zumindest in MT4!

Schau mal der hier: https://www.mql5.com/de/articles/115.

Da die Pipes ja eigentlich auch Files sind, könnte das ein Beispiel sind, wie sie verwendet werden können.

Oder hier?

Oder Du legst eine 'Junction' des Template-Folders dort hin, wo die Mt5-File-Funktionen zugreifen können, so zB.
reteid2222
reteid2222 | 4 Jun 2017 in 11:19
Simply doesn t work in MT4 either!
Carl Schreiber
Carl Schreiber | 4 Jun 2017 in 12:35
reteid2222:
Simply doesn t work in MT4 either!
Doch , ich verwende sie!
Expert Advisors Basierend auf Beliebten Handelssystemen und Alchemie der Handelsroboter Optimierung (Forts.) Expert Advisors Basierend auf Beliebten Handelssystemen und Alchemie der Handelsroboter Optimierung (Forts.)

In diesem Artikel gibt der Autor ein Beispiel eines Expert Advisors, der den Anforderungen gemäß den Regeln der Automated Trading Championship 2008 entspricht

Gruppierte Dateioperationen Gruppierte Dateioperationen

Manchmal ist es erforderlich, identische Operationen mit einer Gruppe an Dateien durchzuführen. Wenn Sie eine Liste mit in einer Gruppe enthaltenen Dateien haben, dann ist es kein Problem. Wenn Sie die Liste jedoch selber erstellen müssen, kommt eine Frage auf: "Wie kann ich das machen?" Der Artikel schlägt vor, dies mit den in der kernel.23.dll enthaltenen Funktionen FindFirstFile() und FindNextFile() zu machen.

Überlagerung und Interferenz bei Finanztiteln Überlagerung und Interferenz bei Finanztiteln

Je mehr Faktoren das Verhalten eines Währungspaares beeinflussen, desto schwieriger ist es, dessen Verhalten zu bewerten und zukünftige Prognosen zu bilden. Wenn wir also die Komponenten eines Währungspaares, die Werte einer nationalen Währung, die sich mit der Zeit ändern, extrahieren könnten, könnten wir den möglichen Bewegungsraum einer nationalen Währung verglichen mit dem Währungspaar mit dieser Währung, sowie die Anzahl der Faktoren, die ihr Verhalten beeinflussen, stark eingrenzen. Als Ergebnis würden wir die Genauigkeit hinsichtlich des erwarteten Verhaltens sowie zukünftiger Prognosen erhöhen können. Wie können wir das machen?

Baukasten des Händlers: Gestaltung der Indikatoren Baukasten des Händlers: Gestaltung der Indikatoren

In diesem Artikel finden Sie die wichtigsten Aufgaben, die es zu erledigen gilt, wenn es um die Gestaltung von Indikatoren geht, sowie auch Lösungen und Automatisierungen dafür.