
Gruppierte Dateioperationen
Einführung
Es ist kein Problem eine Datei zu lesen oder zu schreiben. Auch wenn Sie WinAPI dafür nutzen, wie es in dem Artikel Dateioperationen über WinAPI beschrieben ist. Aber was sollen wir machen, wenn wir nicht den genauen Namen der Datei kennen, nur seine Lage in einem bestimmten Ordner und seine Erweiterung? Natürlich, wir können den erforderlichen Namen manuell eingeben, als einen Parameter, aber was sollen wir machen, wenn es zehn oder mehr solcher Dateien gibt? Wir benötigen eine Methode der gruppierten Verarbeitung der Dateien vom gleichen Typ in dem angegebenen Ordner. Diese Aufgabe kann mit den in der kernel32.dll enthaltenen Funktionen FindFirstFile(), FindNextFile() und FindClose() effizient gelöst werden.
Funktion FindFirstFile()
Die Beschreibung der Funktion ist in msdn angegeben auf: http://msdn.microsoft.com/en-us/library/aa364418(VS.85).aspx.
HANDLE WINAPI FindFirstFile( __in LPCTSTR lpFileName, __out LPWIN32_FIND_DATA lpFindFileData );
Aus dieser Beschreibung ergibt sich, dass die Funktion den Deskriptor der gefundenen und die Suchbedingungen erfüllenden Datei zurückgibt. Die Suchbedingung wie in der Variable lpFileName bestimmt, die den Pfad für die Suche nach der Datei und einen möglichen Namen der Datei enthält. Diese Funktion ist praktisch, da wir die Suche über eine Maske angeben können, zum Beispiel, finde Datei durch die Maske quot;C:\Ordner\*.txt". Die Funktion wird die erste in dem Ordner von "C:\folder" gefundene Datei mit der Erweiterung txt zurückgeben.
Das zurückgegebene Ergebnis ist vom Typ 'int' in MQL4. Um den Eingabe-Parameter zu übergeben, können wir den 'string' Typ verwenden. Jetzt müssen wir klären, was wir an die Funktion als zweiten Parameter übergeben, und wie der Parameter später verarbeitet wird. Die Funktion wir in etwa wie folgt importiert:
#import "kernel32.dll" int FindFirstFileA(string path, .some second parameter); #import
Hier sehen wir die bereits bekannte Bibliothek der kernel32.dll. Allerdings ist Funktionsname angegeben als FindFirstFileA(), nicht als FindFirstFile(). dies kommt durch die Tatsache, dass viele Funktionen in dieser Bibliothek zwei Versionen haben: zum Arbeiten mit Strings in Unicode, ist der Buchstabe 'W' (FindFirstFileW) an den Namen angefügt, während für die Arbeit mit ANSI der Buchstabe 'A' (FindFirstFileA) angefügt ist..
Jetzt müssen wir den zweiten Parameter klären, der beschrieben wird als:
lpFindFileData [out] - Ein Zeiger (Pointer) zu der WIN32_FIND_DATA Struktur der Informationen über eine gefundene Datei oder ein Verzeichnis empfängt.
Es bedeutet, das es der Zeiger zu einer bestimmten Struktur von WIN32_FIND_DATA ist. In diesem Fall ist die Struktur ein bestimmter Bereich in dem PC RAM. Der Zeiger zu diesem Bereich (Adresse) wird an die Funktion übergeben. Wir können Speicher in MQL4 mit einem Datenarray zuordnen. Der Zeiger wird mit dem '&' Zeichen bestimmt. Wir müssen nur die Größe des erforderlichen Speichers in Byte kennen, um den Zeiger an ihn zu übergeben. Im Folgenden ist die Struktur-Beschreibung.
typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; TCHAR cFileName[MAX_PATH]; TCHAR cAlternateFileName[14]; } WIN32_FIND_DATA,
In MQL4 gibt es keine Typen DWORD, TCHAR oder FILETIME. DWORD ist bekannt, dass es 4 Byte belegt, wie int in MQL4, TCHAR hat eine interne Darstellung von einem Byte. Um die Gesamtgröße der Struktur WIN32_FIND_DATA in Bytes zu berechnen, müsse wir nur klären, was FILETIME ist.
typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME
Es stellt sich heraus, dass FILETIME zwei DWORDs enthält, was bedeutet, dass DWORD 8 Bytes belegt. Tabellieren wir das alles:
Typ | Größe in Bytes |
---|---|
DWORD | 4 |
TCHAR | 1 |
FILETIME | 8 |
Jetzt können wir die Größe der Struktur von WIN32_FIND_DATA berechnen und visualisieren was und wo wir es gefunden haben.
Typ |
Größe in Bytes | Hinweis |
---|---|---|
dwFileAttributes | 4 | Dateiattribute |
ftCreationTime | 8 | Datei/Ordner Zeitpunkt der Erstellung |
ftLastAccessTime | 8 | Zeitpunkt des letzten Zugriffs |
ftLastWriteTime | 8 | Zeitpunkt letztes Schreiben |
nFileSizeHigh | 4 | Maximale Größe in Bytes |
nFileSizeLow | 4 | Minimale Größe in Bytes |
dwReserved0 | 4 | Ist in der Regel nicht definiert und nicht verwendet |
dwReserved1 | 4 | Ist reserviert für die Zukunft |
cFileName[MAX_PATH] | 260 (MAX_PATH = 260) | Dateiname |
cAlternateFileName[14] | 14 | Alternativer Name in dem 8.3 Format |
Also ist die Gesamtgröße der Stuktur: 4 + 8 + 8 + 8 + 4 + 4 + 4 +4 + 260 +14 = 318 Bytes.
Wie Sie aus der obigen Abbildung erkennenukönnen, beginnt der Dateiname mit dem 45ten Byte, die vorhergehenden 44 Bytes enthalten verschiedene zusätzliche Informationen. Es ist erforderlich an die Funktion FindFirstFile() eine Struktur mit einer MQL Größe als 310 Byte zu übergeben, als zweiten Parameter. Es wäre am komfortabelsten ein Array des 'int' Typs zu verwenden, das eine Größe nicht kleiner als das benötigte haben sollte. Sie dividieren 318 durch 4 (weil die interne Darstellung des 'int' Typs 4 Byte ist), erhalten 79,4, runden es auf den nächsten größeren Integer und sehen, dass wir ein Array aus 80 Elementen benötigen.
Der Funktion-Import selbst wird nun wie folgt aussehen:
#import "kernel32.dll" int FindFirstFileA(string path, int & answer[]); #import
Hier verwenden wir die Version der Funktion mit dem Buchstaben 'A' am Ende des Namens, FindFirstFileA(), für ANSI-Kodierung. Das 'answer' Array wird durch einen Link übergeben und die dazu mit der Struktur von WIN32_FIND_DATA gefüllt werden. Ein beispielhafter Aufruf:
int win32_DATA[80]; int handle = FindFirstFileA(TerminalPath() + "\experts\*.mq4",win32_DATA);
Funktionen FindNextFileA() und FindClose()
Die Funktion FindNextFileA() empfängt , als ersten Parameter, den 'handle' der vorläufig durch die Funktion FindNextFileA() oder einen anderen, früheren Aufruf zu FinNextFileA() erhaltene Datei. Der zweite Parameter ist der gleiche. Die Funktion FindClose() schließt einfach die Suche. Aus diesem Grund wird das vollständige Erscheinungsbild des Datenimports durch Funktionen wie folgt sein:
#import "kernel32.dll" int FindFirstFileA(string path, int & answer[]); bool FindNextFileA(int handle, int & answer[]); bool FindClose(int handle); #import
Jetzt müssen wir lediglich erfahren, wie man den Namen einer in das Array 'answer[]' geschrieben Datei extrahieren.
Abrufen des Dateinamen
Der Dateiname ist in dem Array beginnen ab dem 45. bis zu dem 304. Byte enthalten. Der 'int' Typ enthält 4 Byte, also enthält das Array 4 Zeichen, wenn wir davon ausgehen, dass das Array mit Zeichen ausgefüllt ist. Also, um auf das erste Zeichen im Dateinamen zu verweisen, sollten wir 44/4 = 11 Elemente von dem 'answer[]' Elemente des 'answer[]' Array überspringen. Der Dateiname ist innerhalb eie Kette aus 65 (260/4=65) Array Elementen, beginnend bei 'answer [11]' (Indexierung beginnt mit Null) und endend mit 'answer [76'].
So können wir aus dem Array 'answer[]' den Dateinamen in Blöcken von 4 Zeichen erhalten. Die 'int' Zahl stellt eine Reihe von 32 Bits dat, die ihrerseits 4 Blöcke mit je 8 Bits darstellt.
Das jüngste Byte steht auf der rechten Seite, das älteste auf der linken. Bits sind in aufsteigender Reihenfolge nummeriert, das heißt, Bits von dem 1ten bis zu dem 8ten ergeben das jüngste Byte. Wir können die benötigten Bytes mit bitweisen Operationen entnehmen. Um den Wert des jüngste Byte zu erhalten, müssen wir die Nullwerte aller Bits füllen, von dem 9ten bis zu dem 32ten. Dies wird ausgeführt mit der logischen Operation AND.
int a = 234565; int b = a & 0x000000FF;
Hier ist 0x000000FF das 32-bit integer das Null-Werte an allen Stellen hat, beginnend von dem 9ten, während die Stellen 1 bis 8 gleich Eins sind. Somit wird die erhaltene Anzahl b nur ein Byte (das jüngste) Byte der Zahl a enthalten. Wir ändern das erhaltene Byte (den Zeichencode) in einen ein-Zeichen String mit der Funktion CharToStr().
Ok, wir haben das erste Zeichen erhalten. Wie können wir das nächste erhalten? Sehr einfach: Wir machen eine bitweise 8-Bit Verschiebung nach rechts, und das zweite Bit ersetzt das jüngste Bit. Dann werden wir die bereits bekannte logische AND Operation anwenden.
int a = 234565; int b = (a >>8) & 0x000000FF;
Wie Sie sich vorstellen können, wird das dritte Bit durch Verschiebung von 16-Bit erhalten, während das älteste durch die Verschiebung von 24-Bit erhalten wird. Somit können wir 4 Zeichen aus einem Element des Array vom 'int' Typ entnehmen. Im Folgenden wird gezeigt, wie Sie die ersten 4 Zeichen des Dateinamen aus dem 'answer[]' Array erhalten:
string text=""; int pos = 11; int curr = answer[pos]; { text = text + CharToStr(curr & 0x000000FF) +CharToStr(curr >> 8 & 0x000000FF) +CharToStr(curr >> 16 & 0x000000FF) +CharToStr(curr >> 24 & 0x000000FF); } Print("text = ", text);
Erstellen wir eine separate Funktion, die einen Text-String von dem übergebenen Array mit dem Namen 'buffer' zurückgibt.
//+------------------------------------------------------------------+ //| read text from buffer | //+------------------------------------------------------------------+ string bufferToString(int buffer[]) { string text=""; int pos = 10; for (int i=0; i<64; i++) { pos++; int curr = buffer[pos]; text = text + CharToStr(curr & 0x000000FF) +CharToStr(curr >> 8 & 0x000000FF) +CharToStr(curr >> 16 & 0x000000FF) +CharToStr(curr >> 24 & 0x000000FF); } return (text); }
Somit ist das Problem des Abrufens des Dateinamens von der Struktur gelöst.
Die Liste Aller Expert Advisors mit Ihrem Quellcode erhalten
Ein einfaches Skript demonstriert die Eigenschaften der obigen Funktionen:
//+------------------------------------------------------------------+ //| CheckFindFile.mq4 | //| Copyright © 2008, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2008, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" #property show_inputs #import "kernel32.dll" int FindFirstFileA(string path, int& answer[]); bool FindNextFileA(int handle, int& answer[]); bool FindClose(int handle); #import //+------------------------------------------------------------------+ //| script program start function | //+------------------------------------------------------------------+ int start() { //---- int win32_DATA[79]; int handle = FindFirstFileA(TerminalPath() + "\experts\*.mq4",win32_DATA); Print(bufferToString(win32_DATA)); ArrayInitialize(win32_DATA,0); while (FindNextFileA(handle,win32_DATA)) { Print(bufferToString(win32_DATA)); ArrayInitialize(win32_DATA,0); } if (handle>0) FindClose(handle); //---- return(0); } //+------------------------------------------------------------------+ //| read text from buffer | //+------------------------------------------------------------------+ string bufferToString(int buffer[]) { string text=""; int pos = 10; for (int i=0; i<64; i++) { pos++; int curr = buffer[pos]; text = text + CharToStr(curr & 0x000000FF) +CharToStr(curr >> 8 & 0x000000FF) +CharToStr(curr >> 16 & 0x000000FF) +CharToStr(curr >> 24 & 0x000000FF); } return (text); } //+------------------------------------------------------------------+
Hier, nach den FindFirstFileA() und FindNextFileA() Funktionsaufrufen, ist das Array win32_DATA (Struktur WIN32_FIND_DATA) geändert zu einem auf einen "leer (empty)" Status geändert, nämlich, alle Elemente des Array sind mit Nullen gefüllt:
ArrayInitialize(win32_DATA,0);
Wenn wir dies nicht machen, kann es passieren, dass die "Fetzen" des Dateinamens des vorherigen Aufrufs die Verarbeitung durchdringen, und wir nur Geschwafel erhalten.
Beispiel-Umsetzung: Erstellen von Quellcode Sicherungen
EI einfaches Beispiel, das praktische Merkmale des obigen veranschaulicht, ist die Erstellung von Quellcode-Sicherungen in einem speziellen Verzeichnis. Dazu müssen wir die Funktionen dieses Artikels mit denen in dem Artikel Dateioperationen über WinAPI kombinieren. Wir erhalten dann das einfache, im Folgenden angegebene Skript backup.mq4. Sie finden den vollständigen Code in der angehangenen Datei. Hier ist nur seine start() Funktion, die alle beschriebenen Funktionen beider Artikel verwendet:
//+------------------------------------------------------------------+ //| script program start function | //+------------------------------------------------------------------+ int start() { //---- string expert[1000]; // must be enough string EAname=""; // EA name int EAcounter = 0; // EAs counter int win32_DATA[80]; int handle = FindFirstFileA(TerminalPath() + "\experts\*.mq4",win32_DATA); EAname = bufferToString(win32_DATA); expert[0] = EAname; ArrayInitialize(win32_DATA,0); int i=1; while (FindNextFileA(handle,win32_DATA)) { EAname = bufferToString(win32_DATA); expert[i] = EAname; ArrayInitialize(win32_DATA,0); i++; if (i>=1000) ArrayResize(expert,2000); // now it will surely be enough } ArrayResize(expert, i); int size = i; if (handle>0) FindClose(handle); for (i = 0 ; i < size; i++) { Print(i,": ",expert[i]); string backupPathName = backup_folder + "experts\\" + expert[i]; string originalName = TerminalPath() + "\\experts\\" + expert[i]; string buffer=ReadFile(originalName); WriteFile(backupPathName,buffer); } if (size > 0 ) Print("There are ",size," files were copied to folder "+backup_folder+"experts\\"); //---- return(0); } //+------------------------------------------------------------------+
Fazit
Es wurde gezeigt, wie man Operationen mit einer Gruppe von Dateien des gleichen Typs durchführt. Sie können lesen und Dateien mit den obigen Funktionen verarbeiten und Ihre eigene Logik umsetzen. Sie können zeitnahe Sicherungen mit einem Expert Advisor machen oder zwei Sätze Dateien in verschiedenen Ordner synchronisieren, Kurse aus Datenbanken importieren, und so weiter. Es ist empfohlen die Verwendung von DLLs zu steuern und nicht die Verbindung zu Bibliotheken von Drittanbieter-Dateien mit der Erweiterung ex4 zu aktivieren. Sie müssen sicherstellen, dass das von Ihnen gestartete Programm nicht die Daten auf Ihrem PC beschädigen wird.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1543





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.