English Русский Español 日本語 Português
preview
Von den Grundlagen bis zur Mittelstufe: Navigation durch die Sandbox

Von den Grundlagen bis zur Mittelstufe: Navigation durch die Sandbox

MetaTrader 5 — Beispiele |
22 0
CODE X
CODE X

Einleitung

Im vorherigen Artikel „Von den Grundlagen bis zur Mittelstufe: Direkter Dateizugriff (II)“ wurde gezeigt, wie wir mit Dateien arbeiten können und dabei den wahlfreien Zugriff auf die darin enthaltenen Daten oder Informationen gewährleisten. Es wurde außerdem erläutert und veranschaulicht, dass dasselbe Konzept nicht immer zum gleichen Ergebnis führt, wenn man nur den Inhalt einer Datei betrachtet. Betrachtet man jedoch die im Terminal angezeigten Ergebnisse, gibt es keine Unterschiede zwischen den einzelnen Implementierungen, da die Implementierung selbst im Wesentlichen dafür sorgt, dass die Ergebnisse angepasst und auf die erwarteten Ergebnisse abgestimmt werden.

Die Art und Weise, wie Sie mit Dateien arbeiten, ändert sich insgesamt nicht wesentlich, und es wird davon ausgegangen, dass Sie verstehen, dass jede Datei intern strukturiert ist, jedoch ohne expliziten Hinweis auf den Datentyp, der beim Anzeigen des Dateiinhalts sichtbar wird. Damit können wir nun den ersten Teil abschließen, in dem es um den Zugriff auf Dateien und die Arbeit mit ihnen ging. In der Praxis müssen Sie die Dokumentation der jeweiligen Sprache lesen, um die in dieser Sprache verfügbaren Funktionen und Prozeduren möglichst effektiv nutzen zu können.

Bitte verstehen Sie mich nicht falsch, lieber Leser. Sie werden wahrscheinlich daran interessiert sein zu sehen, wie die einzelnen MQL5-Funktionen und -Prozeduren verwendet werden, aber meiner Meinung nach wird das nicht besonders hilfreich sein. Im Gegenteil: Ein solcher Ansatz würde den Inhalt der Artikel in einen starren Rahmen zwängen und sie dadurch langweilig und eintönig machen. Der Punkt ist: Auch wenn ich sage, dass wir diese erste Einführung in das Thema Dateien als abgeschlossen betrachten können, haben wir dieses Thema noch nicht abgeschlossen. Das liegt daran, dass sich alles, was wir bisher behandelt haben, auf die von MetaTrader 5 unterstützten Sandboxes beschränkt. Im Grunde genommen bewegen wir uns immer noch auf der Ebene des Benutzerzugriffs.

Es gibt jedoch noch eine weitere Zugriffsebene: den Zugriff auf Anwendungsebene. Darauf gehen wir später ein. Bei dieser Unterscheidung zwischen Benutzerzugriff und Zugriff auf Anwendungsebene ergeben sich daher einige recht komplexe Probleme, die weit über die durch die Verwendung von Sandboxes auferlegten Regeln hinausgehen. Da fängt es an, kompliziert zu werden. Vor allem dann, wenn man nicht versteht, wie das Sandbox-System in MetaTrader 5 funktioniert. Darauf sind wir bereits in früheren Artikeln eingegangen.

Bevor wir zu diesem Thema übergehen – das die Sache für einige von Ihnen erheblich verkomplizieren wird –, müssen wir zunächst bestimmte Prozeduren und Funktionen erläutern. Das liegt daran, dass sie bei der Arbeit mit Dateien äußerst nützlich sind, da sie uns ermöglichen, Vorgänge auszuführen, die sonst nicht möglich wären. Um dieses Thema richtig zu verstehen, kommen wir nun zum Hauptthema dieses Artikels.


Navigation durch Dateien und Verzeichnisse

Auch wenn viele diese Suchaufgabe vielleicht für unnötig halten – und für die meisten Anwendungen ist sie das sicherlich auch –, gibt es doch ganz bestimmte Situationen in der Programmierung, sowohl hier bei der Entwicklung für MetaTrader 5 als auch in anderen Umgebungen, in denen wir eine Suche in einem Verzeichnisbaum und seinen Dateien implementieren müssen. Zu verstehen, wie man dabei vorgeht, gehört wahrscheinlich zu den routinemäßigsten und schematischsten Aufgaben, denen Sie begegnen können. Das liegt daran, dass es in vielen Fällen sehr eintönig und in gewisser Weise langweilig ist. Dennoch ist es wichtig zu wissen, wie man solche Aufgaben angeht.

Aufgrund bestimmter Besonderheiten der Programmierung für MetaTrader 5 können wir eine Suche auf zwei verschiedene Arten durchführen. Die eine erfolgt im interaktiven Modus, während die andere sozusagen automatisch arbeitet. Im interaktiven Modus wird ein Dialogfeld verwendet, das einem kleinen Dateiauswahlfenster ähnelt. Die automatische Methode hingegen nutzt die von MQL5 bereitgestellten Funktionen, um auf Betriebssystemprozeduren für die Suche im Dateisystem zuzugreifen.

Zunächst werden wir eines der Skripte, die wir im vorherigen Artikel betrachtet haben, auf sehr einfache und unkomplizierte Weise anpassen. Das wird uns helfen zu verstehen, wie der interaktive Zugriff sowie die Suche nach Dateien und Verzeichnissen funktionieren werden. Der geänderte Code ist im Folgenden vollständig aufgeführt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int handle;
07.     const datetime dt = D'31.10.2024 15:30:10';
08.     const int i32 = 356248;
09.     string filenames[];
10. 
11.     if (FileSelectDialog("Save as...", NULL, "All files (*.*)|*.*", FSD_WRITE_FILE, filenames, "Hello Word.txt") <= 0)
12.         return;
13. 
14.     if ((handle = FileOpen(filenames[0], FILE_WRITE| FILE_READ | FILE_ANSI)) == INVALID_HANDLE)
15.     {
16.         Print("Error...");
17.         return;
18.     };
19. 
20.     FileWrite(handle, i32, "Info", dt);
21. 
22.     FileFlush(handle);
23.     
24.     FileSeek(handle, 0, SEEK_SET);
25.     while (!FileIsEnding(handle))
26.         Print(FileTell(handle), " >> ", FileReadString(handle));
27. 
28.     FileClose(handle);
29. }
30. //+------------------------------------------------------------------+

Code 01

„Ich verstehe das nicht. An welcher Stelle im Code genau wurden die Änderungen vorgenommen? Auf den ersten Blick ist dies genau derselbe Code wie in den Beispielen, die wir im vorherigen Artikel besprochen haben.“ Die Änderungen sind sehr geringfügig und haben auf den ersten Blick keine nennenswerten Auswirkungen auf den Code. Viele glauben, dass die Entwicklung neuen Codes eine radikale Überarbeitung erfordert, aber in der Praxis gehen wir nicht immer so vor. Im Grunde ist die Änderung hier sehr leicht zu verstehen, und sie befindet sich in Zeile 11. Auch wenn die Änderung nur Zeile 11 betrifft, wird bei der Ausführung dieses Codes etwas anderes passieren. Zunächst öffnet die Funktion FileSelectDialog ein Fenster, wie unten dargestellt:

Abbildung 01

In dem in Abbildung 01 gezeigten Fenster, das vom Betriebssystem bereitgestellt und verwaltet wird, lassen sich bestimmte Elemente leicht erkennen. Zunächst einmal der Fenstertitel. Wie Sie sehen, ist dies genau derselbe Titel, den wir als erstes Argument der Funktion FileSelectDialog angegeben haben. Da das zweite an die Funktion übergebene Argument NULL ist, beginnen wir im Stammverzeichnis der Sandbox. Achtung, lieber Leser: Da wir uns innerhalb der Sandbox befinden, KÖNNEN WIR NICHT das Verzeichnis – oder genauer gesagt: das aktuelle Stammverzeichnis – verlassen. Mit anderen Worten: Sie können nicht frei durch alle Verzeichnisse auf dem Laufwerk navigieren, auf dem MetaTrader 5 installiert ist. Daher sind wir auf die Verzeichnisstruktur der aktuellen Sandbox beschränkt.

Als drittes Argument der Funktion übergeben wir einen Filter, mit dem sich die Suchergebnisse im Suchfenster eingrenzen lassen. Sie können nur die Filter auswählen, die hier in Zeile 11 aufgeführt sind. Daher sollten Sie nicht davon ausgehen, dass das Betriebssystem die Verwendung von Filtern zulässt, die hier nicht aufgeführt sind, denn das wird nicht der Fall sein. Das nächste Argument der Funktion sind die Auswahl-Flags. Es ist wichtig, hier ein wenig mit den anderen Flags zu experimentieren, um zu verstehen, welche Ergebnisse sie liefern und wozu sie dienen, da wir damit viel mehr tun können, als nur einen Dateinamen oder Ähnliches anzugeben. In der Dokumentation erfahren Sie, welche Werte hier für die Flags verwendet werden können.

Gut, nun müssen wir uns die letzten beiden Argumente der Funktion FileSelectDialog ansehen. Dieser Abschnitt kann je nach Art der Implementierung, an der Sie arbeiten, geringfügig variieren. Im Grunde genommen muss das fünfte Argument jedoch immer ein dynamisches Array vom Typ „string“ sein. Der Grund dafür ist, dass die Funktion dieses Array mit Daten über die Interaktion des Benutzers mit dem in Abbildung 01 dargestellten Dialogfeld füllt. Das letzte Argument muss wiederum nicht unbedingt so aussehen wie in Code 01. Wenn Sie jedoch einen bestimmten Dateinamen verwenden möchten, müssen Sie diesen hier angeben. Auf diese Weise haben wir schließlich eine Vorstellung davon, welchen Standardnamen unsere Anwendung erwartet. Man sollte nicht vergessen, dass der Benutzer diesen Namen ändern kann.

Gut, wenn alles reibungslos verläuft, gibt die Funktion einen Wert größer als null zurück. Sollte dies nicht der Fall sein, bedeutet dies, dass ein Fehler aufgetreten ist, und wir müssen das Skript beenden. Dies geschieht in Zeile 12. Wenn dies gelingt und wir die Datei speichern möchten, fahren wir mit Zeile 14 fort, wo der Code wieder genauso funktioniert wie im vorherigen Artikel. Beachten Sie jedoch, dass beim Erstellen oder Öffnen einer Datei mit der Funktion FileOpen das erste übergebene Argument genau der erste im Array enthaltene Wert ist. Dieses Array kann verwendet werden, um mehrere vom Benutzer ausgewählte Dateien zu speichern. Die Dateien werden vom Benutzer ausgewählt, wenn der Aufruf in Zeile 11 erfolgt. Wie bereits erwähnt, müssen Sie ein wenig üben, um besser zu verstehen, wie Sie die Funktion FileSelectDialog in Ihren Anwendungen für MetaTrader 5 einsetzen können.

Gut, ich denke, diese kurze Erklärung vermittelt Ihnen bereits einen ersten Eindruck davon, wie Sie die interaktive Navigation durch den Datei- und Verzeichnisbaum verstehen und üben können. Um die Themen voneinander zu trennen, sehen wir uns daher in einem eigenen Abschnitt an, wie die nicht interaktive Navigation funktioniert.


Codebasierte Navigation

In manchen Situationen möchten wir nicht, dass der Benutzer direkt mit dem Suchmechanismus interagiert. Gleichzeitig möchten wir jedoch aus irgendeinem Grund wissen, wie der Verzeichnisbaum aufgebaut ist – sowohl in Bezug auf die Dateien als auch auf die Verzeichnisstruktur selbst. Um dies jedoch zu erreichen, lassen wir das, was wir in Code 01 gesehen haben, beiseite und setzen eine andere Lösung um. Wir tun dies mit einem ganz bestimmten Ziel vor Augen.

Da es hier darum geht, so didaktisch wie möglich vorzugehen – ohne dabei eine bestimmte Anwendung entwickeln zu wollen –, ist es ziemlich schwierig zu erklären, warum wir durch einen Verzeichnisbaum navigieren wollen. Ich möchte jedoch, dass Sie, lieber Leser, versuchen, Ihren Horizont zu erweitern und die Welt jenseits dessen zu sehen, was hier in Form von Code präsentiert wird. Versuchen Sie einmal, sich eine Anwendung vorzustellen, die daran interessiert wäre, zu erfahren, wie die Dateistruktur aufgebaut ist. Denken Sie vor diesem Hintergrund darüber nach, wie Sie dies in der Praxis anwenden könnten.

Super. Um loszulegen – und damit Sie besser verstehen, wie diese Art der Navigation funktioniert – gehen wir davon aus, dass das Sandbox-Verzeichnis „MQL5\Files“ leer ist. Mit anderen Worten: Derzeit befinden sich keine Dateien oder Verzeichnisse in der Sandbox. Es ist wichtig, mit diesem Grundsatz zu beginnen, damit alles Sinn ergibt. Vor diesem Hintergrund beginnen wir mit dem unten gezeigten Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     long    handle;
07.     string  szFileName;
08. 
09.     if ((handle = FileFindFirst("*", szFileName)) == INVALID_HANDLE)
10.     {
11.         Print("Failed...");
12.         return;
13.     }
14.     do
15.     {
16.         Print(szFileName, " is a ", FileIsExist(szFileName) ? "file ..." : "directory...");
17.     }while (FileFindNext(handle, szFileName));
18.     FileFindClose(handle);
19. 
20.     Print("Search in directory completed successfully.");
21. }
22. //+------------------------------------------------------------------+

Code 02

Denken Sie daran: Alle unsere Aktionen sind auf die Sandbox beschränkt, in der wir arbeiten. Grundsätzlich ist es nicht möglich, Dateien oder Verzeichnisse außerhalb der Sandbox zu durchsuchen. Vergessen Sie das nicht. Wenn wir also Code 02 ausführen, erhalten wir das folgende Ergebnis:

Abbildung 02

„Mein Gott, was ist hier passiert? Wie konnte der Code versagen? Was habe ich getan, um das zu verdienen? Das kann nur eine göttliche Strafe sein.“ (LACHEN) Beruhigen Sie sich, lieber Leser; lassen Sie uns nichts überstürzen. Der Code enthält keine Fehler; alles funktioniert einwandfrei. „Wie ist das möglich? Sehen Sie denn nicht, dass ein Fehler aufgetreten ist?“ Noch einmal: Überstürzen wir nichts. Erinnern Sie sich noch daran, was gesagt wurde, bevor wir angefangen haben? Sollte das Verzeichnis MQL5\Files, das wir hier als Sandbox verwenden, also grundsätzlich komplett leer sein?

Da die Funktion FileFindFirst in der Sandbox nichts gefunden hat, gibt sie einen ungültigen Handle-Wert zurück. Mit anderen Worten: Da für den Filter keine Übereinstimmung gefunden wurde, gibt FileFindFirst einen Wert zurück, der anzeigt, dass die Suche erfolglos war. Genau aus diesem Grund sehen wir das in Abbildung 02 dargestellte Ergebnis. Es ist nämlich so: Wenn Sie Code 01 jetzt noch einmal ausführen, wird Folgendes angezeigt.

Abbildung 03

„Okay, ich glaube, ich verstehe das. Was aber, wenn sich Inhalte in der Sandbox befinden? Was passiert dann?“ Das hängt davon ab, wie unser Code aufgebaut ist, um mit den Inhalten der Sandbox umzugehen. Da es sich hier um etwas sehr Einfaches und Unkompliziertes handelt, wird das Ergebnis an dieser Stelle ebenso einfach und unkompliziert ausfallen. Je nach konkreter Situation kann jedoch eine etwas anspruchsvollere Lösung erforderlich sein. Schauen wir uns jedenfalls zunächst einmal an, was passiert, wenn sich Inhalte in der Sandbox befinden. Zu diesem Zweck haben wir mehrere Dateien und Ordner ausschließlich zu Testzwecken angelegt. Wir können dies überprüfen, indem wir Code 01 erneut ausführen. In diesem Fall ist das Ergebnis in der folgenden Abbildung dargestellt:

Abbildung 04

Nun gibt es also etwas zu zeigen. Wenn wir Code 02 erneut ausführen, erhalten wir das unten gezeigte Ergebnis:

Abbildung 05

Bitte beachten Sie, dass wir am Code überhaupt nichts geändert haben; wir haben lediglich Inhalte zur Sandbox hinzugefügt. An dieser Stelle wird die Sache jedoch etwas komplizierter. Das hängt natürlich davon ab, was genau Sie umsetzen möchten. Obwohl Code 02 funktioniert, wie Sie in den vorangegangenen Abbildungen sehen können, gibt es noch ein kleines Detail. Code 02 bezieht sich nur auf das anfängliche Suchverzeichnis. Er kann nicht in andere Verzeichnisse des Verzeichnisbaums hinabsteigen, um deren Inhalte anzuzeigen. Sie müssen angeben, dass Sie auf ein bestimmtes Verzeichnis zugreifen möchten. Dies geschieht bereits, bevor die Suche beginnt, die in Zeile 09 startet. In manchen Fällen schränkt dies die Möglichkeiten etwas ein.

Halten wir einen Moment inne und überlegen wir, woran das liegt. Der Grund dafür ist, dass die Lösung für die Navigation durch den Verzeichnisbaum in Code 02 selbst enthalten ist. Damit jedoch alles so funktioniert, wie wir es uns vorstellen, müssen wir ein paar kleine Änderungen am Code vornehmen. Mit anderen Worten: Der Code muss in der Lage sein, alle Dateien aufzulisten, die in jedem Verzeichnis des Sandbox-Verzeichnisbaums vorhanden sind.

Sehr gut, wir wissen nun, dass wir bei der Angabe eines Filters für die Funktion FileFindFirst einen Pfad innerhalb der Sandbox einbeziehen können. Was wäre, wenn wir genau diesen Code 02 in rekursiven Code umwandeln würden? Werden wir das gewünschte Verhalten erzielen? Somit kann uns Zeile 16 von Code 02 den Namen jeder Datei und ihren Speicherort liefern. Das ist also die wichtigste Frage, die wir jetzt beantworten müssen. Man sollte bedenken, dass es mehrere Möglichkeiten gibt, das zu tun, was ich Ihnen hier gleich zeigen werde. Jeder Fall ist anders.

Als Erstes müssen Sie also den Code so ändern, dass er in etwa wie unten gezeigt aussieht:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (FileIsExist(szFileName)) Print(szFileName);
22.     }while (FileFindNext(handle, szFileName));
23.     FileFindClose(handle);
24. }
25. //+------------------------------------------------------------------+

Code 03

Das ist der erste Schritt. Also, lieber Leser, passen Sie jetzt gut auf. Wenn Sie diesen Code ausführen, wird das Ergebnis von dem oben gezeigten abweichen. Das liegt daran, dass wir uns derzeit ausschließlich auf die Anzeige von Dateinamen konzentrieren. Es ist sehr wichtig, dass Sie das genau verstehen. Sie haben wahrscheinlich erwartet, etwas Ähnliches zu sehen wie in der Adressleiste des Datei-Explorers, wo sowohl der Verzeichnispfad als auch der Dateiname angezeigt werden. Was Sie jedoch sehen, ist lediglich die Art und Weise, wie das Betriebssystem oder das Programm den Inhalt anzeigt. Intern, d. h. innerhalb der auf der Festplatte gespeicherten Ordner- und Dateistruktur, ist sie anders organisiert.

Tatsächlich ähnelt das Dateisystem sehr einer Liste oder einem Telefonbuch. Vielleicht begannen das Problem und all diese Verwirrung mit der Veröffentlichung von Windows 95. Zu dieser Zeit kam die Idee auf, den Verzeichnisbaum als Teil des Dateinamens zu verwenden. In der Praxis läuft das aber nicht ganz so ab. Eine Erläuterung hierzu würde jedoch den Rahmen dieses Artikels sprengen. Kommen wir nun zurück zu unserem Hauptthema. Das Ergebnis der Ausführung von Code 03 ist in der folgenden Abbildung dargestellt:

Abbildung 06

Bitte beachten Sie, dass hier nur die Dateinamen angezeigt werden. Diese Verzeichnisse werden gerade deshalb nicht angezeigt, weil wir im Moment kein Interesse an ihnen haben. Angenommen, die in Abbildung 05 dargestellten Verzeichnisse enthalten Inhalte – wie könnten wir diese dann anzeigen? Das ist der einfachste Teil. Bevor wir jedoch darauf eingehen, beachten Sie bitte, dass bei der Angabe eines Verzeichnisses das letzte Zeichen ein Schrägstrich ist. Das ist sehr wichtig für das, was wir als Nächstes sehen werden.

Mit anderen Worten: Wenn sich die Zeichenkette szFileName auf ein Verzeichnis bezieht, enthält sie einen Schrägstrich. Daher müssen wir die Funktion FileIsExist nicht verwenden, um festzustellen, ob es sich um ein Verzeichnis oder eine Datei handelt. Überprüfen Sie einfach, ob die Zeichenkette einen Schrägstrich enthält. Wenn er vorhanden ist, handelt es sich um ein Verzeichnis. Andernfalls handelt es sich um eine Datei. So einfach ist das.

Ich möchte Sie jedoch bitten, hier in Code 03 auf ein weiteres Detail zu achten. Beachten Sie, dass die Prozedur in Zeile 11 eine Zeichenkette als Argument entgegennimmt. Dies ist das Ausgangsverzeichnis, in dem wir die Suche durchführen werden. In Zeile 06 übergeben wir jedoch keine Parameter an die Prozedur in Zeile 11. Das bedeutet, dass die Suche im Stammverzeichnis der Sandbox beginnt. Es ist sehr wichtig, dies zu verstehen, denn hier beginnt der rekursive Teil des Codes.

Denken Sie daran: Wenn wir eine Zeichenkette auf das Vorhandensein eines Schrägstrichs überprüfen, prüfen wir damit, ob die Zeichenkette auf ein Verzeichnis verweist. Was wäre, wenn wir den Code so ändern, dass er diese Informationen nutzt? Mit anderen Worten: Anstatt die Information zu ignorieren, dass die Zeichenkette einen Verzeichnisnamen enthält, würden wir den Aufruf von SearchIn in Zeile 11 so ändern, dass er den Inhalt dieser Zeichenkette verwendet, der in diesem Fall bekanntermaßen ein Verzeichnis bezeichnet. Was passiert hier? Sehen wir uns nun an, wie das in der Praxis funktioniert. Auf der Grundlage dieser Idee können wir Code 03 wie unten gezeigt anpassen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szFileName);
23.         else
24.             Print(szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Code 04

Super. In Code 04 sehen wir die Änderungen, die am Code vorgenommen wurden, um das zuvor Erläuterte umzusetzen. Wenn wir also Code 04 ausführen, erhalten wir ein völlig anderes Ergebnis als das, das wir in Abbildung 06 gesehen haben. Dennoch wird das Ergebnis dem in Abbildung 06 gezeigten sehr ähnlich sein. Einige werden das Ergebnis verständlich finden, während andere vielleicht verwirrt sind. Zur Verdeutlichung können Sie sich die unten stehende Abbildung 07 ansehen:

Abbildung 07

Also, wo ist der Haken? Gut, wenn Sie sich Abbildung 07 ansehen, könnten Sie dann sagen, zu welchem Ordner die Datei „Backup.zip“ gehört? Man könnte sagen, dass sie zum Ordner „Sub 02“ gehört. Bei genauerer Betrachtung lässt sich jedoch feststellen, dass etwas Ähnliches auch bei den Ordnern „Sub 01“ und „Sub 11“ passiert ist. „Aber Moment mal. Das ist viel komplizierter, als ich gedacht hatte. Wenn ich mir Abbildung 04 anschaue, stelle ich fest, dass sich der Ordner „Sub 02“ genau wie der Ordner „Sub 01“ im Stammverzeichnis befindet. Wenn ich mir die Darstellung in Abbildung 07 jedoch so anschaue, habe ich den Eindruck, dass sich die Datei „Backup.zip“ eigentlich unter dem Pfad Sub 01\Sub 11\Sub 02 befinden sollte. Das scheint mir nicht richtig zu sein. Jetzt bin ich ein wenig verwirrt.“

Bei diesem Ansatz wird es etwas schwierig, genau zu verstehen, wie der Verzeichnisbaum in der Sandbox aufgebaut ist. Also, jetzt zeige ich Ihnen, wie er aufgebaut ist. Das wird Ihnen helfen zu verstehen, wie das Ergebnis dargestellt werden sollte. Die folgende Animation veranschaulicht dies:

Animation 01

Animation 01 zeigt deutlich eine sehr einfache Ordnerstruktur sowie eine Datei, die in Abbildung 07 nicht zu sehen ist. Auf den ersten Blick erscheint das ziemlich seltsam. Abbildung 07 zeigt, dass die Datei „Backup.zip“ angezeigt wird, obwohl sie sich in einem Verzeichnis befindet. Wo liegt also der Fehler? Der Fehler besteht darin, dass wir in Zeile 22 von Code 04 die Verzeichnisstruktur außer Acht lassen. Tatsächlich greifen wir nur auf die Verzeichnisse selbst zu, ohne den Verzeichnisbaum zu berücksichtigen. Die Lösung für solche Probleme ist ganz einfach – und sogar ein wenig trivial, wenn man einmal darüber nachdenkt.

Wir werden jedoch noch eine weitere Änderung am Code vornehmen. Bei der Ausgabe des Dateinamens fügen wir den Pfad hinzu, unter dem die Datei gefunden wurde. Auf diese Weise erhalten wir eine Struktur, die insgesamt leichter zu verstehen ist. Daraus ergibt sich folgender Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szDir + szFileName);
23.         else
24.             Print(szDir, szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Code 05

Führen wir nun den oben gezeigten neuen Code aus. Das Ergebnis lautet wie folgt.

Abbildung 08

Nun haben wir etwas ziemlich Interessantes erreicht. Beachten Sie, dass wir durch eine einfache Änderung in Code 04, mit der wir das in Code 05 gezeigte Ergebnis erhalten, letztendlich zu einem völlig anderen – und sogar viel interessanteren – Ergebnis gelangt sind. Wenn Sie möchten, können Sie sogar Zeile 16 aus dem Code entfernen und trotzdem nachvollziehen, wie die Verzeichnisstruktur aufgebaut ist, und sich veranschaulichen, wo sich die einzelnen Dateien befinden. Das ist interessant. Allerdings gibt es bei Code 05 sozusagen ein kleines, aber ziemlich lästiges Problem. Der Code selbst funktioniert, wie Sie deutlich sehen können. Es gibt jedoch eine ganz bestimmte Situation, in der Verzeichnisse und Dateien vermischt erscheinen können. Dies ist weder ein Fehler im Code noch ein Softwarefehler. Das ist eine andere Art von Problem.

Dies hängt insbesondere damit zusammen, wie die Funktionen FileFindFirst und FileFindNext zusammenwirken. Es geht darum, dass das System beim Aufruf der Funktion FileFindFirst vom Betriebssystem ein Ergebnis anfordert, das dem angegebenen Filter entspricht. Das Ergebnis kann eine Datei oder ein Verzeichnis sein. Theoretisch lässt sich nicht steuern, welches Element zuerst zurückgegeben wird. Dies wird vom Betriebssystem festgelegt. Das Problem entsteht jedoch, wenn wir erneut nach dem nächsten Element fragen. Dies erfolgt mithilfe der Funktion FileFindNext. Wo liegt also das Problem? Gut, nehmen wir an, wir möchten zunächst alle Dateien durchgehen, bevor wir zu den Verzeichnissen wechseln, oder umgekehrt. Wie lässt sich das erreichen? Beachten Sie bitte, dass wir keinen Einfluss darauf haben, welche Art von Element uns das Betriebssystem zurückgibt. Wir erhalten nur dieses eine Element und entscheiden dann selbst, was wir damit machen.

Nun, lieber Leser, um Probleme wie diese zu lösen, müssen wir einen anderen Ansatz wählen. Im nächsten Artikel werden wir uns näher mit diesem Thema befassen.


Abschließende Gedanken

Im heutigen Artikel haben wir uns eine einfache, unkomplizierte und praktische Methode angesehen, wie man den Inhalt der Sandbox mit MetaTrader 5 anzeigen kann. Auch wenn das, was wir hier sehen, auf den ersten Blick vielleicht nicht besonders bedeutungsvoll oder zielgerichtet erscheint – zumindest in dieser Anfangsphase. Wenn man weiß – und vor allem versteht –, wie man mithilfe von Code den Inhalt eines Ordners oder des gesamten Stammverzeichnisses anzeigt, kann dies dabei helfen, bestimmte Daten, die in unzähligen Dateien und Ordnern verborgen sind, schnell zu finden.

Das Hauptziel besteht darin, zu verstehen, wie man mit diesen Ausgaben arbeitet, um das Thema des nächsten Artikels besser nachvollziehen zu können. Gehen Sie also noch einmal sorgfältig und in Ruhe durch, was Sie in diesem Artikel bereits gelesen haben, damit Sie verstehen, was wir im nächsten Artikel behandeln werden. Als Nächstes wenden wir uns einem sehr interessanten Thema zu, auch wenn es für diejenigen, die gerade erst mit dem Programmieren anfangen, vielleicht etwas einschüchternd wirken mag. Bis zum nächsten Artikel.

Datei Beschreibung
Code 01 Zeigt, wie man zwischen Ordnern navigiert.
Code 02 Zeigt, wie man zwischen Ordnern navigiert.
Code 03 Zeigt, wie man zwischen Ordnern navigiert.

Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/16322

Beigefügte Dateien |
Anexo.zip (1.59 KB)
Die Übertragung der Trading-Signale in einem universalen Expert Advisor. Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
In diesem Artikel wurden die verschiedenen Möglichkeiten beschrieben, um die Trading-Signale von einem Signalmodul des universalen EAs zum Steuermodul der Positionen und Orders zu übertragen. Es wurden die seriellen und parallelen Interfaces betrachtet.
Von den Grundlagen bis zur Mittelstufe: Direkter Dateizugriff (II) Von den Grundlagen bis zur Mittelstufe: Direkter Dateizugriff (II)
In diesem Artikel untersuchen wir, wie zwei leicht unterschiedliche Ansätze die gesamte Implementierungsstrategie erheblich beeinflussen können – sowohl im Hinblick auf die Leistung als auch die Konzeption der Datenträger-Ein-/Ausgabe – und dabei zugleich helfen, Kompatibilitätsprobleme zwischen Anwendungen zu vermeiden.
Eine alternative Log-datei mit der Verwendung der HTML und CSS Eine alternative Log-datei mit der Verwendung der HTML und CSS
In diesem Artikel werden wir eine sehr einfache, aber leistungsfähige Bibliothek zur Erstellung der HTML-Dateien schreiben, dabei lernen wir auch, wie man eine ihre Darstellung einstellen kann (nach seinem Geschmack) und sehen wir, wie man es leicht in seinem Expert Advisor oder Skript hinzufügen oder verwenden kann.
MQL5 meistern – Vom Anfänger zum Profi (Teil VII): Grundlagen des Debuggings von MQL-Anwendungen MQL5 meistern – Vom Anfänger zum Profi (Teil VII): Grundlagen des Debuggings von MQL-Anwendungen
Debugging ist ein wesentlicher Bestandteil des Programmierzyklus. In diesem Artikel werden gängige Techniken für das Debugging jeder Anwendung behandelt, die in der MetaTrader-5-Umgebung ausgeführt wird.