English Русский Español Português
preview
Von der Grundstufe zur Mittelstufe: FileSave und FileLoad

Von der Grundstufe zur Mittelstufe: FileSave und FileLoad

MetaTrader 5Beispiele |
15 0
CODE X
CODE X

Einführung

Im vorigen Artikel „Von der Grundstufe zur Mittelstufe: Sandbox und MetaTrader“ wurde das Konzept der Sandbox und ihre Auswirkung auf den MetaTrader 5-Workflow bei der Verwendung von MQL5-Bibliotheksfunktionen und -prozeduren zum Erstellen, Verarbeiten und Lesen von Dateien im Allgemeinen auf sehr einfache und praktische Weise erklärt.

Dieses Material war nur dazu gedacht, zu erklären, was die Sandbox ist, nicht um optimale Methoden für die Arbeit mit Dateien zu demonstrieren. Dies liegt daran, dass es weitaus effizientere Möglichkeiten gibt, dies mit reinem MQL5 zu implementieren, ohne auf Betriebssystemfunktionen angewiesen zu sein.

Unter der Annahme, dass der Leser bereits mit dem Sandbox-Konzept und dessen Auswirkung auf den Workflow vertraut ist, können wir dazu übergehen, mit Dateien zu arbeiten, um unterschiedliche Ergebnisse zu erzielen. Es sei darauf hingewiesen, dass es in diesem Material nicht um die Entwicklung einer bestimmten Anwendung geht. Um zu demonstrieren, wie bestimmte Aufgaben implementiert werden können, verwenden wir nur einige wenige Funktionen und Prozeduren aus der MQL5-Bibliothek. Dennoch müssen Sie das Material selbst in der Praxis anwenden, um bestimmte Nuancen zu verstehen, die möglicherweise Fragen aufwerfen. Lassen Sie uns also, unserer üblichen Tradition folgend, zu einem neuen Thema übergehen und die Grundlagen untersuchen.


Es gibt keine einzige universelle Formel

Im vorigen Artikel haben wir ein Lese-/Schreibschema für eine ziemlich einfache Aufgabe implementiert, und an diesem Punkt hätte der Code so belassen werden können, wie er war. In der Praxis folgen reale Implementierungen jedoch nicht immer dem Beispiel, das wir zuvor gezeigt haben. Dies liegt daran, dass ein bestimmtes Problem auftreten kann. Um den Kontext wiederherzustellen, lassen Sie uns noch einmal genau betrachten, worum es bei diesem Problem geht. Dazu verwenden wir eines der Codebeispiele, die im vorigen Artikel besprochen wurden. Es ist nachfolgend aufgeführt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     const string szText = "This file was created by a script written in MQL5.";
07.     uchar info[];
08. 
09.     StringToCharArray(szText, info);
10. 
11.     FileSave("Hello.txt", info);
12. }
13. //+------------------------------------------------------------------+

Code 01

Wenn Code 01 ausgeführt wird, erstellt er eine Datei, deren Inhalt in der folgenden Abbildung dargestellt ist.

Abbildung 01

Abbildung 01 zeigt ein ungewöhnliches Zeichen – in diesem Fall das Nullzeichen (NUL). Es wird verwendet, um das Ende eines Strings zu markieren, und im Kontext einer Anwendung, die diese Art der String-Darstellung verwendet, ist dies kein Problem. In einer Datei, die zur Speicherung von Klartext gedacht ist, ergibt ein solches Zeichen jedoch keinen Sinn und wird je nach Zweck oder beabsichtigter Verwendung der Textdatei oft zu einem Problem.

Es gibt mehrere Möglichkeiten, diese Art von Problem zu lösen. Einige sind direkter, während andere indirekt sind und zusätzliche Schritte erfordern, um korrekt implementiert zu werden. Darüber hinaus gibt es eine weitere Nuance im Zusammenhang mit Code 01. Obwohl Zeile 11 eine Datei erstellen und Daten auf die einfachste und direkteste Weise direkt hineinschreiben kann, schafft diese Vorgehensweise ein weiteres Problem, das wir in Kürze im Detail untersuchen werden: den wahlfreien Zugriff auf Dateidaten.

Obwohl diese Aussage ungewöhnlich erscheinen mag, funktionieren Dateien auf Datenträgern in der Praxis nicht wie Systeme mit sequentiellem Lesen, wie dies beispielsweise bei Dateien auf Magnetbändern der Fall ist. Bei einem Band müssen Sie oft einen erheblichen Teil des Bandes lesen, wenn Sie eine Datei oder bestimmte Daten lesen möchten, was den Lese- und Schreibvorgang manchmal erheblich erschwert. Bei Dateien, die auf einem Datenträger gespeichert sind, sind jedoch sowohl sequenzieller als auch wahlfreier Zugriff möglich, wodurch jeder Teil der Datei jederzeit gelesen oder geschrieben werden kann.

Trotz dieser Möglichkeit sind FileSave und FileLoad jedoch keine geeigneten Funktionen für den wahlfreien Zugriff, da sie eine Datei als vollständigen Block lesen oder schreiben und normalerweise die gesamte Datei auf den Datenträger laden oder speichern. Bei kleinen Dateien ist dies kein Problem, und wenn der Dateiinhalt zugunsten des Überschreibens ignoriert werden kann, können Anwendungen FileSave und FileLoad ohne wirkliche Probleme verwenden, da sie eine sehr praktische und sichere Möglichkeit zum Lesen und Schreiben von Dateien bieten.

Wenn die Aufgabe jedoch darin besteht, eine Datei zu ändern und dabei einen Teil ihres Inhalts unverändert zu lassen, ist die Verwendung von FileSave und FileLoad möglicherweise nicht die beste Lösung, da in diesem Fall die gesamte Datei im Arbeitsspeicher gehalten werden muss. Dies kann völlig unpraktisch sein, da oft nur ein kleines Fragment, an dem direkt gearbeitet wird, im Arbeitsspeicher gehalten werden muss. Der Rest kann auf dem Datenträger verbleiben und bei Bedarf geladen werden.

Aus diesem Grund gibt es keine einzelne universelle Formel oder einen universellen, endgültigen Weg zur Implementierung von Aufgaben. Jeder Fall ist einzigartig, und die gewählte Lösung sollte entsprechend den Anforderungen des jeweiligen Falls ausgewählt werden, damit die Erfahrung des Benutzers mit Ihren MetaTrader 5-Anwendungen komfortabel und praktikabel bleibt.

Um das oben Gesagte einfacher und klarer verständlich zu machen, sollten wir einige einfache Beispiele erstellen, die zeigen, warum jede Implementierung individuell gestaltet werden muss, da viele Leute möglicherweise keine klare Vorstellung davon haben, wie stark bestimmte Entscheidungen die Art und Weise beeinflussen können, wie eine Anwendung entwickelt wird.

Beginnen wir damit, neue Informationen zu einer Datei hinzuzufügen, die bereits auf dem Datenträger gespeichert wurde. In diesem Fall ist die verarbeitete Datei genau dieselbe Datei wie die in Code 01 erzeugte. An demselben Code 01 werden jedoch einige Änderungen vorgenommen, um diese Art der Dateiverarbeitung zu ermöglichen. Denken Sie daran: Das Ziel ist es, einer bereits gespeicherten Datei neue Informationen hinzuzufügen. Theoretisch könnten wir also eine Lösung in Betracht ziehen, die der unten gezeigten ähnelt.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SaveInfo("This file was created by a script written in MQL5.");
07.     SaveInfo("New information is being added to the file.");
08. }
09. //+------------------------------------------------------------------+
10. void SaveInfo(const string szArg)
11. {
12.     uchar info[];
13. 
14.     StringToCharArray(szArg, info);
15.     FileSave("Hello.txt", info);
16. }
17. //+------------------------------------------------------------------+

Code 02

Wenn Code 02 ausgeführt wird, erwarten wir, dass die Datei Hello.txt sowohl die Daten aus Abbildung 01 als auch die neuen Informationen enthält. Die Daten, die in der Datei hätten erscheinen sollen, sind in den Zeilen 06 und 07 von Code 02 dargestellt. Beachten Sie, dass dies sehr leicht zu verstehen ist. Wenn dieses Skript jedoch in MetaTrader 5 ausgeführt wird, ist das Ergebnis nicht ganz das, was erwartet wurde. Es ist unten zu sehen:

Abbildung 02

Dies wirft die Hauptfrage auf – und ein ebenso wichtiges Problem. Was könnte passiert sein, um das in Abbildung 02 gezeigte Ergebnis zu erzeugen? Zunächst ist dieses Ergebnis nicht zu erwarten, da sowohl der Inhalt von Zeile 06 als auch der von Zeile 07 in der endgültigen Datei vorhanden sein sollten. Es wird jedoch nur die Nachricht aus Zeile 07 angezeigt.

Mit anderen Worten: Aus irgendeinem Grund wird der Inhalt von Zeile 06 ignoriert und nur der Inhalt von Zeile 07 geschrieben. Dies wirft die Frage auf, was mit dem Inhalt von Zeile 06 geschieht. Dies ist eines der am schwersten zu verstehenden Probleme ohne die Hilfe von jemandem, der die zugrunde liegenden Prozesse im Detail erklären kann. In der Praxis ist es jedoch recht einfach. Wenn Zeile 06 ausgeführt wird, schreibt die Funktion in Zeile 15 Daten in die Datei. Unmittelbar danach, wenn Zeile 07 ausgeführt wird, wird diese Datei überschrieben und ein neuer Inhalt hineingeschrieben. Trotz der Einfachheit dieses Prozesses kann es ohne eine externe Erklärung schwierig sein, herauszufinden, warum der Code bestimmte Daten nicht schreibt. Dies erweckt den falschen Eindruck, dass ein schwerwiegender Fehler im Code vorliegt, während das Problem in Wirklichkeit woanders liegt.

Wie können wir dieses Problem also lösen? Kurz gesagt: Wie könnten wir den Inhalt von Zeile 06 und Zeile 07 in derselben Datei speichern? Nun, lieber Leser, wie bereits im Titel dieses Abschnitts erwähnt: ES GIBT KEINE ALLGEMEINGÜLTIGE FORMEL. Es gibt verschiedene Möglichkeiten, diese Aufgabe zu lösen, jede mit ihren eigenen Vor- und Nachteilen. Hier zeigen wir nur ein Beispiel zur Veranschaulichung. Aber Sie können sich andere Ansätze überlegen und versuchen, diese umzusetzen. Versuchen Sie, Ihre eigene Lösung zu entwickeln, indem Sie FileSave als Ausgangspunkt verwenden. Dies liegt daran, dass es andere, viel einfachere Lösungen gibt, vorausgesetzt, sie sind gut geplant.

Betrachten wir die erste Lösung, die wir vorschlagen könnten. Sie ist unten zu sehen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SaveInfo("This file was created by a script written in MQL5.");
07.     SaveInfo("New information is being added to the file.");
08. }
09. //+------------------------------------------------------------------+
10. void SaveInfo(const string szArg)
11. {
12.     const string FileName = "Hello.txt";
13.     uchar info[], tmp[];
14. 
15.     FileLoad(FileName, info);
16.     StringToCharArray(szArg + "\n", tmp);
17.     ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
18.     FileSave(FileName, info);
19. }
20. //+------------------------------------------------------------------+

Code 03

Nach der Ausführung von Code 03 erhalten wir ein Ergebnis, das diesem sehr ähnlich ist:

Abbildung 03

Nun, das aktuelle Ergebnis entspricht voll und ganz dem, was erwartet wurde. Mit anderen Worten: Sowohl der Inhalt von Zeile 06 als auch der von Zeile 07 werden der Datei hinzugefügt. Aber das ist nicht alles. Sie können auch sehen, dass das zuvor erwähnte NULL-Zeichen nicht mehr hinzugefügt wird. Wie haben wir zwei Probleme auf einmal gelöst?

Darüber hinaus macht eine genauere Analyse deutlich, dass die Prozedur SaveInfo in Zeile 10 von Code 03 praktisch Code zum Erstellen von Protokolldateien ist. Mit anderen Worten: Mit sehr geringem Aufwand oder Kosten können Sie ein System erstellen, das protokolliert, was Ihr Code tut, und diese Informationen in eine Datei schreibt. Dies ermöglicht es Ihnen, im Detail zu untersuchen und zu analysieren, was während der Ausführung passiert. Interessant, nicht wahr? Eine einfach zu implementierende Lösung mit sehr interessanten Ergebnissen und Möglichkeiten.

Lassen Sie uns nun sehen, was hier vorgefallen ist, wodurch es möglich wurde, Code 02 zu korrigieren und Code 03 wesentlich geeigneter zu machen, und vor allem, in der Lage zu sein, den Inhalt von Zeile 06 und Zeile 07 zu speichern.

Um dies zu sehen, beachten Sie, dass eine Konstante hinzugefügt wurde. Dies ermöglicht es uns, dieselbe Referenz auf den Dateinamen zu verwenden, da wir ihn in Zeile 15 lesen und in Zeile 18 schreiben werden. Aber warum das? Nun, der Grund dafür ist, dass FileSave, wie in Code 02 gezeigt, den Inhalt des Puffers in einem einzigen Durchgang schreibt. Kurz gesagt: Wenn der Puffer, der in diesem Fall das Info-Array ist, bestimmte Informationen enthält, überschreiben diese Informationen die ursprünglichen Daten in der Datei. Wenn wir die Datei jedoch lesen, laden wir ihren Inhalt in den Puffer. Unmittelbar danach fügen wir mithilfe von Zeile 17 die neuen Informationen zu dem hinzu, was bereits im ursprünglichen Dateipuffer vorhanden war. Es ist, als würden wir die Datei buchstäblich im Arbeitsspeicher erstellen und sie dann auf dem Datenträger speichern.

In dem Beispiel, das wir betrachten, wird diese Art von Vorgang sehr schnell ausgeführt. Wenn die Dateigröße jedoch zunimmt, wird dies zu einem Problem, da die Durchführung von Lese- und Schreibvorgängen auf diese Weise die Effizienz der Anwendung hinsichtlich der Nutzung von Systemressourcen verringert. Letztendlich wirkt sich dies auf die Ausführungszeit aus, denn je mehr Daten in der Datei vorhanden sind, desto länger dauert das Lesen und Schreiben auf dem Datenträger. Für einfache Fälle wie den hier betrachteten kann diese Lösung jedoch problemlos verwendet werden.

In Ordnung, aber was passiert, wenn wir die Anwendung erneut ausführen? Auf den ersten Blick funktioniert alles ohne Probleme. In diesem Fall werden die Zeilen 06 und 07 immer wieder geschrieben, wodurch immer mehr Zeilen mit denselben Informationen hinzugefügt werden. Dies geht so lange weiter, bis wir die ursprüngliche Datei löschen. Danach beginnt derselbe Ablauf erneut. Mit anderen Worten, wir haben jetzt eine neue Aufgabe. Es gibt zwei Hauptmöglichkeiten, dies im Code zu handhaben. Obwohl es andere Optionen gibt, konzentrieren wir uns hier nur auf zwei.


Erste Lösung

Die erste Lösung für dieses Problem besteht darin, die Datei zu löschen und mit dem Neuschreiben zu beginnen, während die Anwendung läuft. Dazu muss Code 03 durch eine Lösung ersetzt werden, die der unten gezeigten ähnelt.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_FILENAME "Hello.txt"
05. //+------------------------------------------------------------------+
06. void OnStart(void)
07. {
08.     FileDelete(def_FILENAME);
09.     SaveInfo("This file was created by a script written in MQL5.");
10.     SaveInfo("New information is being added to the file.");
11. }
12. //+------------------------------------------------------------------+
13. void SaveInfo(const string szArg)
14. {
15.     uchar info[], tmp[];
16. 
17.     FileLoad(def_FILENAME, info);
18.     StringToCharArray(szArg + "\n", tmp);
19.     ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
20.     FileSave(def_FILENAME, info);
21. }
22. //+------------------------------------------------------------------+

Code 04

Ausgezeichnet, Code 04 löst das Problem, das in Code 03 bestand, teilweise. Es ist jedoch wichtig zu betonen, dass diese Lösung zwar funktionsfähig, aber etwas gefährlich ist. Dies liegt daran, dass schwerwiegende Probleme auftreten können, wenn der Programmierer vergisst, die korrekte Sandbox anzugeben. Der Grund dafür ist, dass Zeile 08 von Code 04 die angegebene Datei tatsächlich löscht. Wenn jedoch der Lesevorgang in Zeile 17 und der Schreibvorgang in Zeile 20 nicht mit Zeile 08 in Bezug auf die verwendete Sandbox übereinstimmen, löschen wir möglicherweise eine Datei, die nicht genau die ist, die wir beabsichtigt haben.

Da Code 04 hier bereitgestellt wird, können Sie ihn ändern, um zu verstehen, welche Arten von Problemen auftreten können, wenn unterschiedliche Sandboxes verwendet werden. Um dieses Problem jedoch zu lösen, können wir eine Definition hinzufügen, die alle Aspekte der Implementierung synchronisiert und so Probleme im Zusammenhang mit der Verwendung unterschiedlicher Sandboxes zu unterschiedlichen Zeitpunkten verhindert. Dies kann wie folgt erfolgen.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #define def_FILENAME        "Hello.txt"
05. #define def_FILE_COMMON                     //If set uses the shared folder
06. //+------------------------------------------------------------------+
07. void OnStart(void)
08. {
09. #ifdef def_FILE_COMMON
10.     FileDelete(def_FILENAME, FILE_COMMON);
11. #else
12.     FileDelete(def_FILENAME);
13. #endif
14.     SaveInfo("This file was created by a script written in MQL5.");
15.     SaveInfo("New information is being added to the file.");
16. }
17. //+------------------------------------------------------------------+
18. void SaveInfo(const string szArg)
19. {
20.     uchar info[], tmp[];
21. 
22. #ifdef def_FILE_COMMON
23.     FileLoad(def_FILENAME, info, FILE_COMMON);
24. #else
25.     FileLoad(def_FILENAME, info);
26. #endif
27.     StringToCharArray(szArg + "\n", tmp);
28.     ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
29. #ifdef def_FILE_COMMON
30.     FileSave(def_FILENAME, info, FILE_COMMON);
31. #else
32.     FileSave(def_FILENAME, info);
33. #endif
34. }
35. //+------------------------------------------------------------------+

Code 05

Bitte beachten Sie, dass wir hier in Code 05 das Synchronisationsproblem auf sehr praktische Weise lösen, einfach deshalb, weil wir in Zeile 05 definieren, welcher Code kompiliert werden soll. Dies vermeidet verschiedene Probleme, die auftreten, wenn man versucht, an einer Stelle auf eine Weise und an einer anderen Stelle auf eine andere Weise auf eine Datei zuzugreifen.

In Ordnung, es sieht so aus, als hätten wir nützliche Änderungen am Code vorgenommen. Aber wenn Sie das, was in diesen Artikeln gezeigt wird, studiert und versucht haben, in die Praxis umzusetzen, haben Sie wahrscheinlich gedacht: Könnte der FileDelete-Aufruf nicht innerhalb der SaveInfo-Prozedur platziert werden? Dies würde die in Code 05 gezeigte Implementierung überflüssig machen und dennoch eine gewisse Synchronisierung der Sandbox selbst bewahren, da alle Bibliotheksfunktionen zusammengefasst wären, was die Änderung des Codes einfacher und schneller macht.

Ja, lieber Leser, dies kann getan werden. Obwohl es nicht genau der traditionelle Weg ist, funktioniert es. Basierend auf dem bisher Gezeigten kann dies mit einer statischen Variablen erfolgen. Ein sicherer Weg wäre die Verwendung von Klassen, aber da wir dieses Konzept noch nicht behandelt haben, werden wir nicht zeigen, wie eine klassenbasierte Lösung implementiert wird. Wir können jedoch eine Lösung zeigen, die eine statische Variable verwendet. Dies geschieht mit folgendem Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SaveInfo("This file was created by a script written in MQL5.");
07.     SaveInfo("New information is being added to the file.");
08. }
09. //+------------------------------------------------------------------+
10. void SaveInfo(const string szArg)
11. {
12. //+----------------+
13. #define def_FILENAME "Hello.txt"
14. //+----------------+
15.     static bool b_Clear = false;
16.     uchar info[], tmp[];
17. 
18.     if (!b_Clear) FileDelete(def_FILENAME);
19.     FileLoad(def_FILENAME, info);
20.     StringToCharArray(szArg + "\n", tmp);
21.     ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
22.     FileSave(def_FILENAME, info);
23.     b_Clear = true;
24. }
25. //+------------------------------------------------------------------+

Code 06

Hören Sie jetzt gut zu. Obwohl Code 06 dem Code 04 sehr ähnlich ist, unterscheidet sich sein Verhalten erheblich. Dies liegt genau an der statischen Variablen, die in Zeile 15 deklariert ist. Aber die Tatsache, dass alle Operationen, die an der Datei durchgeführt werden müssen, an einer Stelle konzentriert sind, nämlich in der Prozedur SaveInfo, macht es viel einfacher, Daten zu finden und entsprechend unseren Anforderungen zu ändern. Auf diese Weise müssen wir nicht den Code nach Stellen durchsuchen, die mit den für diese Datei vorgesehenen Operationen in Konflikt stehen könnten.

In Ordnung, es ist jetzt klar, wie wir mit dem System arbeiten können, indem wir die ursprüngliche Datei löschen. Wir können dies jedoch etwas anders machen und erhalten dennoch das gleiche Ergebnis wie mit den Änderungen, die in diesem Abschnitt vorgenommen und gezeigt wurden. Um dies zu veranschaulichen, gehen wir zu einem neuen Abschnitt über, in dem wir eine zweite Art von Lösung vorstellen werden.


Zweite Lösung

Wie bereits erwähnt, gibt es viele Möglichkeiten, dieses Problem zu lösen. Hier werden wir uns jedoch nur zwei Ansätze ansehen, damit wir nicht bei einer einzigen Lösung hängenbleiben. Über Lösungswege für Probleme nachzudenken, ist die Aufgabe jedes guten Programmierers. Lassen Sie uns nun sehen, wie die zweite Art der Problemlösung aussehen wird. Sie werden überrascht sein, wie einfach sie ist. Ehrlich gesagt sollte die Lösung etwas zwischen Code 03 und Code 06 sein. Um jedoch alles klar zu machen, möchte ich, dass Sie diese Lösung als eine Version von Code 03 nach ein paar einfachen Änderungen betrachten. Diese Änderungen werden im Folgenden dargestellt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SaveInfo("This file was created by a script written in MQL5.");
07.     SaveInfo("New information is being added to the file.");
08. }
09. //+------------------------------------------------------------------+
10. void SaveInfo(const string szArg)
11. {
12.     const string FileName = "Hello.txt";
13.     static bool b_isFirst = true;
14.     uchar info[], tmp[];
15. 
16.     if (b_isFirst)
17.     {
18.         ArrayFree(info);
19.         b_isFirst = false;
20.     }else
21.         FileLoad(FileName, info);
22.     StringToCharArray(szArg + "\n", tmp);
23.     ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
24.     FileSave(FileName, info);
25. }
26. //+------------------------------------------------------------------+

Code 07

Schauen Sie sich jetzt Code 07 an und antworten Sie ehrlich. Verstehen Sie, was dort geschieht? Bitte beachten Sie, dass der Code selbst einer Mischung aus Code 03 und Code 06 sehr ähnlich ist. Im Gegensatz zu Code 06, bei dem wir FileDelete verwendet haben, verwenden wir hier in Code 07 jedoch das Schreibsystem selbst, um die Datei zu leeren, während wir gleichzeitig neue Informationen empfangen, sobald sie eintreffen. Aber wie ist es uns gelungen, dies umzusetzen?

Nun, mein lieber Leser, wenn Sie immer noch Zweifel daran haben, wie dies möglich wurde, sollten Sie wahrscheinlich die ersten Artikel dieser Serie studieren, in denen wir erklärt haben, wie man mit statischen Variablen arbeitet. Obwohl viele Leute statische Variablen für ein schwieriges Thema halten, ist ihr Verständnis extrem wichtig, um verschiedene Aufgaben einfach und reibungslos zu lösen, wodurch der Code zwischen verschiedenen Anwendungen recht portabel wird, während dasselbe Ziel verfolgt wird.

Ich habe statische Variablen in dem Artikel „ Von der Grundstufe bis zur Mittelstufe: Variablen (II)“ besprochen. Da Code 07 sehr einfach ist und Sie die Grundprinzipien seiner Verwendung verstehen, werden wir keine Zeit damit verbringen, zu erklären, wie er aufgebaut ist. Stattdessen werden wir uns eine andere Lösung ansehen, die sehr ähnlich ist, aber ein ziemlich interessantes Ergebnis hat, das eine Erklärung verdient.

In allen Codefragmenten, die wir betrachtet haben, haben Sie wahrscheinlich bemerkt, dass wir immer an eine einzige Datei gebunden waren, deren Name irgendwo im Code definiert war. Sie können sich sogar vorstellen, wie nützlich es wäre, Daten in verschiedenen Dateien zu speichern, ohne irgendwelche Änderungen am Code vornehmen zu müssen.

In den meisten Fällen könnten wir den Namen der zu speichernden Datei einfach als Argument an die Prozedur SaveInfo übergeben. Das wäre eine Möglichkeit, das Problem zu lösen, würde aber gleichzeitig andere Arten von Problemen schaffen, die je nach Art der Aktivität, die unsere Anwendung erwartet und erfordert, mehr oder weniger schwierig zu lösen sein können. Es gibt jedoch einen relativ eleganten Weg, dieses Problem zu lösen, der es ermöglicht, Daten mit geringem Aufwand in verschiedenen Dateien zu speichern.

Dieser Ansatz beinhaltet die Verwendung von strukturierter Programmierung. Wir haben dies bereits in einem kleinen Block von Artikeln innerhalb derselben Serie besprochen. Da dieses Thema bereits in mehreren Artikeln behandelt wurde, werden wir hier keinen Link bereitstellen. Um richtig zu verstehen, wie strukturierte Programmierung tatsächlich funktioniert, müssen Sie das Thema höchstwahrscheinlich von Anfang an studieren. Es wäre jedoch unfair gegenüber denjenigen, die die Artikel verfolgt und die dort präsentierten Informationen studiert haben, nicht zu zeigen, wie das Problem bei der Wahl des Dateinamens zum Speichern gelöst werden kann.

Lassen Sie uns also für diejenigen, die bereits mit den Grundlagen der strukturierten Programmierung vertraut sind, sehen, wie der Code aussehen würde, um eine weitaus bessere Lösung als die bisher gesehenen zu erhalten, die zudem weniger Datenträgerzugriffe erfordert, wie in Code 07. Die Lösung ist unten dargestellt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct stFile
05. {
06.     private :
07.         string  FileName;
08.         int     common_flag;
09.         bool    b_isFirst;
10.     public  :
11. //+----------------+
12.         void SetFileName(const string szArg, const int iArg = 0)
13.         {
14.             FileName = szArg;
15.             common_flag = iArg;
16.             b_isFirst = true;
17.         }
18. //+----------------+
19.         void SaveInfo(const string szArg)
20.         {
21.             uchar info[], tmp[];
22. 
23.             if (FileName == NULL) return;
24.             if (b_isFirst)
25.             {
26.                 ArrayFree(info);
27.                 b_isFirst = false;
28.             }else
29.                 FileLoad(FileName, info, common_flag);
30.             StringToCharArray(szArg + "\n", tmp);
31.             ArrayCopy(info, tmp, info.Size(), 0, tmp.Size() - 1);
32.             FileSave(FileName, info, common_flag);
33.         }
34. //+----------------+
35. };
36. //+------------------------------------------------------------------+
37. void OnStart(void)
38. {
39.     stFile  file;
40. 
41.     file.SetFileName("Hello.txt");
42.     file.SaveInfo("This file was created by a script written in MQL5.\nStructured programming version.");
43.     file.SaveInfo("New information is being added to the file.\nFile saved in the local directory.");
44. 
45.     file.SetFileName("Hello.txt", FILE_COMMON);
46.     file.SaveInfo("This file was created by a script written in MQL5.\nStructured programming version.");
47.     file.SaveInfo("New information is being added to the file.\nFile saved in shared directory.");
48. }
49. //+------------------------------------------------------------------+

Code 08

Code 08 ist sehr interessant und sogar ziemlich fesselnd, da er mehrere Konzepte gleichzeitig anwendet. Dies geschieht, damit wir eine sehr spezifische Aufgabe haben. Da viele Leute, selbst diejenigen, die versucht haben, die Artikel zu studieren, in denen wir erklärt haben, wie strukturierte Programmierung funktioniert, Zweifel daran haben könnten, wie dieser Code an bestimmten Stellen arbeitet, werden wir einige interessante Aspekte kurz erläutern. Es sollte jedoch beachtet werden, dass ein großer Teil des Codes stark an Code 07 erinnert. Aber hier machen wir etwas Komplexeres und daher meiner Meinung nach viel Besseres.

Beachten Sie, dass wir in Zeile 04 eine Struktur deklariert haben. Dies dient als Grundlage für das, was wir tun werden. Innerhalb der Struktur haben wir mehrere private Felder und zwei Prozeduren. Die Prozedur in Zeile 12 wird verwendet, um den Namen der Datei anzugeben, mit der wir zu einem bestimmten Zeitpunkt arbeiten. Darüber hinaus ermöglicht sie uns, die von uns verwendete Sandbox zu ändern. Nun beginnt also der etwas komplexere Teil dieser ersten Phase.

Da wir mit strukturiertem Code anstelle einer Klasse arbeiten, können wir bestimmte Aktionen nicht ausführen. Wir können jedoch andere Techniken anwenden. In diesem Fall initialisiert der Compiler, wenn er den Mechanismus zur Speicherzuweisung für die zwischen den Zeilen 07 und 09 deklarierten Variablen erstellt, auch die Werte vor. Es ist sehr wichtig zu wissen, welchen Anfangswert dieser Speicherbereich haben wird. Strings werden normalerweise mit null initialisiert. Dies ermöglicht die Durchführung des in Zeile 23 gezeigten Tests.

Der Zweck dieses Tests besteht darin, sicherzustellen, dass eine Datei zur Verwendung angegeben wurde – mit anderen Worten, dass ein Dateiname festgelegt wurde. Der Grund ist folgender: Wenn wir nicht angegeben haben, welche Datei verwendet werden soll, dann greift diese Prüfung, und die Prozedur SaveInfo wird sofort beendet. Der Rest des Codes ist sehr einfach, da er bereits in anderen Teilen dieses Artikels behandelt wurde.

Lassen Sie uns jedoch zur OnStart-Prozedur übergehen, da hier einige Erklärungen erforderlich sind, damit Sie Code 08 ordnungsgemäß studieren können.

Bitte beachten Sie, dass wir in Zeile 39 eine Variable erstellt haben, um die in Zeile 04 definierte Struktur zu verwenden. Wenn dann Zeile 41 ausgeführt wird, legen wir fest, welche Datei wir von diesem Punkt an verwenden werden. Achten Sie darauf, lieber Leser. Ohne Zeile 41 hätten die nachfolgenden Aufrufe keine praktische Auswirkung.

Der interessante Punkt befindet sich jedoch in Zeile 45. In diesem Stadium leiten wir den Informationsfluss, der zuvor an die in Zeile 41 definierte Datei gerichtet war, an denselben Dateinamen in einer anderen Sandbox um. Aber das ist nicht alles. Bitte beachten Sie, dass der Dateiname trotz allem derselbe ist wie der in Zeile 41 angegebene. Hier weisen wir MetaTrader 5 jedoch an, den Datenfluss in eine andere Sandbox umzuleiten.

Können wir das tun? Ja, das ist möglich, lieber Leser. Beachten Sie, dass wir den Datenfluss unabhängig davon, wie der Code implementiert werden sollte oder kann, problemlos an jede uns zur Verfügung stehende Datei weiterleiten können, sofern wir Schreibzugriff in der angegebenen Sandbox haben.

In der Praxis ist dies weitaus interessanter, als es dieser Code vermuten lässt. So sehr, dass bei der Ausführung von Code 08 zwei Dateien erstellt werden, wie unten dargestellt.

Abbildung 04

Abbildung 05

Bitte beachten Sie, dass die Inhalte unterschiedlich sind, ebenso wie das grün hervorgehobene Verzeichnis.


Abschließende Überlegungen

In diesem Artikel haben wir gesehen, dass es kein allgemeingültiges Rezept für die Arbeit mit Dateisystemen gibt. Wir haben begonnen, etwas in die Praxis umzusetzen, das vielen Menschen schwierig erscheinen mag, aber mit Zeit, Studium und Hingabe werden Sie Freude daran finden, auf den Geschmack kommen und sich sicher fühlen. Es gibt keine magische Lösung. Die Essenz liegt darin, verschiedene Konzepte so anzuwenden, dass am Ende ein spezifisches Ergebnis erzielt wird.

Achten Sie also, lieber Leser, darauf, das hier Gesehene zu studieren und zu üben. Ein richtiges Verständnis, kombiniert mit ständiger Übung und der kontinuierlichen Suche nach neuen Wegen, um dasselbe zu erreichen, ist das, was Ihnen das nötige Wissen vermittelt. Im Anhang finden Sie den Code zum Studieren und Üben der hier vorgestellten Informationen. Verwenden Sie den Code jedoch nicht genau so, wie er im Anhang bereitgestellt wird. Versuchen Sie, den Code zu modifizieren, insbesondere Code 08, um besser zu verstehen, wie sich die Zeilen 41 und 45 auf das Gesamtergebnis der Ausführung auswirken. In Zukunft, nachdem Klassen erklärt wurden, werden wir sehen, dass Code 08 ein großes Potenzial für Verbesserungen und eine einfachere Verwendung hat, vorausgesetzt, er wird korrekt angepasst. Aber dafür müssen Sie zuerst verstehen, wie dieser strukturierte Code arbeitet.

MQ5-Datei Beschreibung
Code 01
 Demonstration des Dateizugriffs
Code 02   Demonstration des Dateizugriffs 
Code 03   Demonstration des Dateizugriffs
Code 04   Demonstration des Dateizugriffs
Code 05   Demonstration des Dateizugriffs
Code 06   Demonstration des Dateizugriffs
Code 07   Demonstration des Dateizugriffs
Code 08   Demonstration des Dateizugriffs

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

Beigefügte Dateien |
Anexo.zip (3.58 KB)
Community of Scientists Optimization (CoSO): Theorie Community of Scientists Optimization (CoSO): Theorie
Geheimnisse der effektiven Optimierung von Handelsstrategien in metaheuristischen Ansätzen. Community of Scientists Optimization ist ein neuer populationsbasierter Algorithmus, der von den Mechanismen der wissenschaftlichen Gemeinschaft inspiriert ist. Im Gegensatz zu traditionellen, von der Natur inspirierten Metaphern modelliert CoSO einzigartige Aspekte menschlicher wissenschaftlicher Tätigkeit: das Veröffentlichen von Ergebnissen in Fachzeitschriften, das Konkurrieren um Fördermittel und das Bilden von Forschungsteams.
Quantenneuronales Netzwerk in MQL5 (Teil II): Training eines neuronalen Netzwerkes mit Backpropagation unter Verwendung von ALGLIB-Markov-Matrizen Quantenneuronales Netzwerk in MQL5 (Teil II): Training eines neuronalen Netzwerkes mit Backpropagation unter Verwendung von ALGLIB-Markov-Matrizen
Der Artikel präsentiert eine innovative Architektur für ein quantenneuronales Netz für den algorithmischen Handel, die die Prinzipien der Quantenmechanik mit modernen Methoden des maschinellen Lernens kombiniert. Das System umfasst Quanteneffekte (Resonanz, Interferenz, Dekohärenz), mehrstufiges Gedächtnis verschiedener Zeitskalen, Markov-Ketten mit der ALGLIB-Bibliothek und adaptive Parametersteuerung. Die vollständige Implementierung erfolgt in MQL5 unter Verwendung der integrierten Matrix-/Vektortypen, was Implementierungshürden in MetaTrader 5 beseitigt.
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.
Kompetitiver Lernalgorithmus (CLA) Kompetitiver Lernalgorithmus (CLA)
Der Artikel stellt den kompetitiven Lernalgorithmus (Competitive Learning Algorithm, CLA) vor, eine neue metaheuristische Optimierungsmethode, die auf der Simulation des Bildungsprozesses basiert. Der Algorithmus organisiert die Population von Lösungen in Klassen mit Schülern und Lehrern, wobei Agenten durch drei Mechanismen lernen: Lernen vom Besten der Klasse, Lernen aus eigener Erfahrung und Wissensaustausch zwischen Klassen