Lucrul cu fisiere. Partea a III-a
[English version] [MQLmagazine.com in english] [Editia romaneasca]
Acesta este al treilea articol din seria de articole intitulate ‘Lucrul cu fisiere’ si tin sa va anunt ca este unui dintre cele mai importante articole din serie deoarece voi prezenta atat functiile de scriere in fisiere cat si exemple prin care voi evidentia anumite aspecte ale functiilor.
Functiile care se refera strict la scrierea in fisiere sunt in numar de 8. Aceste functii sunt:
1 2 | FileWrite() , FileWriteArray() , FileWriteDouble() , FileWriteFloat() , FileWriteInteger() , FileWriteLong() , FileWriteString() , FileWriteStruct() |
In continuarea articolului va voi prezenta fiecare functie in parte cu observatiile de rigoare. Acestea fiind spuse sa trecem la treaba.
FileWrite()
Functia se foloseste pentru scrierea datelor in fisiere de tip CSV. Prototipul functiei este:
1 2 3 4 | uint FileWrite( int file_handle // referinta fisierului ... // Lista cu parametrii de scris ); |
Parametrul file_handle reprezinta rezultatul intors de functia FileOpen() , functie care trebuie apelata cu flagurile FILE_CSV|FILE_WRITE. Daca fisierul nu este deschis cu flagul FILE_WRITE functia FileWrite() va esua.
Lista de parametri de scris in fisierul CSV nu poate fi mai mare de 63 , parametrii vor fi separati de delimitatorul specificat cand am deschis fisierul cu functia FileOpen(). Daca nu specificam delimitatorul atunci acesta va fi implicit caracterul ‘tab’ (ASCII 9).
Tipul parametrilor nu este specificat, ei putand fiind integer , datetime , float , … .Este important sa stim ca functia FileWrite() converteste in siruri de caractere parametrii primiti. Parametrii de tip double au 16 cifre dupa virgula , parametrii de tip float au 5 , iar parametrii de tip datetime sunt convertiti in formatul ‘YYYY.MM.DD HH:MI:SS’.
Fiecare comanda FileWrite() pune la sfarsitul stringului generat ‘\r\n’. Acest lucru arata ca imediat dupa scrierea stringului cursorul a fost mutat pe linia urmatoare la capat de rand.
1 2 | int file_handle=FileOpen("text.csv",FILE_ANSI|FILE_CSV|FILE_WRITE); uint chars_written=FileWrite(file_handle,1,3,4,5,6,7); |
In Excel 2007 , desi delimitatorul este ‘tab’ si parametrii de inregistrat ar trebui sa fie afisati pe cate o coloana separata ei nu apar. Daca redenumim fisierul ca fiind ‘.txt’ si il deschidem cu Excel 2007 atunci parametrii pe cate o coloana deorece recunoaste caracterul ‘tab’. Problema este din cauza Excel si nu merita studiata. Este recomandat sa deschideti fisierul CSV cu un editor precum notepad sau notepad++ in cazul in care are mai mult de 65535 linii.
FileWriteArray()
Functia scrie elementele din tablouri de diferite tipuri , cu exceptia celor de tip string , in fisiere deschise ca FILE_BIN.
Prototipul functiei este:
1 2 3 4 5 6 | int FileWriteArray( int file_handle // Referinta fisierului void array[], // Tabloul int start_item=0, // Indexul elementului din tablou int items_count=WHOLE_ARRAY // Numarul de elemente ); |
Parametrii functiei sunt: file_handle , rezultatul intors de functia FileOpen(); array , tabloul din care extrag elementele pentru scrierea in fisier ; start_item , locul din tablou de unde incepe scrierea ; items_count , numarul de elemente pe pe care il copiez incepand de la start_item.
Rezultatul intors de functia FileWriteArray() este numarul de elemente scrise in fisier , rezultatul intors de functie trebuie sa fie egal cu items_count pentru ca functia sa fi avut o executie corecta.
Daca tabloul are 9 elemente si-i trimitem items_count mai mare ca 9 , functia FileWriteArray() nu va intoarce o eroare , ea va scrie cele 9 elemente.
Mai jos aveti un exemplu de cod care scrie o matrice intr-un fisier de tip bin (deschis cu FILE_BIN):
1 2 3 | double array1[3][3]={{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}}; int file_handle=FileOpen("text.bin",FILE_BIN|FILE_WRITE); int elements_written=FileWriteArray(file_handle,array1,0,WHOLE_ARRAY); |
Tablourile de tip string trebuie scrise in fisiere TXT. Filecare element , la scrierea in fisier, este urmat de characterele ‘\r\n’ , deci fiecare element al matricei o sa fie scris pe o noua linie. Mai jos am exemplificat intr-un cod functionalitatea FileWriteArray() in cazul in care matricea pe care vreau sa o scriu este de tip string.
1 2 3 | string array1[3][3]={{"a", "b", "c"}, {"d", "e", "f"}, {"g", "h", "i"}}; int file_handle=FileOpen("text.txt",FILE_TXT|FILE_WRITE|FILE_ANSI); int elements_written=FileWriteArray(file_handle,array1,6,3); |
FileWriteDouble()
Functia scrie intr-un fisier la pozitia curenta a cursorului o valoare de tip double. Prototipul functiei este :
1 2 3 4 | uint FileWriteDouble( int file_handle // Referinta fisierului double dvalue // Valoarea pe care dorim sa o scriem ); |
Parametrii functiei sunt doi la numar: file_handle este referinta catre fisierul deschis intors de FileOpen() si dvalue este valoarea de tip double pe care dorim sa o scrie in fisier.
Functia se executa cu succes daca rezultatul intors este 8 , adica lungimea in bytes a unei variabile de tip double si pointerul se muta cu 8 bytes.
Mai jos aveti un exemplu de cod.
1 2 | fh=FileOpen("test.bin",FILE_WRITE|FILE_BIN); s=FileWriteDouble(fh,a); |
Atentie: Pentru a folosi functia FileWriteDouble() fisierul trebuie deschis in modul binar , altfel functia esueaza la executie.
FileWriteFloat()
Functia FileWriteFloat() este asemanatoare cu FileWriteDouble() , numai ca tipul de variabila pe care il scriem in fisier este de tip float. Prototipul functiei este:
1 2 3 4 | uint FileWriteFloat( int file_handle // Referinta fisierului float fvalue // Valoarea pe care dorim sa o scriem ); |
Parametrii functiei sunt file_handle , referinta fisierului dat de functia FileOpen() si valoarea de tip float pe care dorim sa o scriem in fisierul nostru.
Exemplu de cod:
1 2 | fh=FileOpen("test.bin",FILE_WRITE|FILE_BIN); s=FileWriteFloat(fh,a); |
Desigur, rezultatul trebuie sa fie 4, lungimea in bytes a unei variabile de tip float, pentru o scriere corecta.
FileWriteInteger()
Functia scrie o variabila de tip integer intr-un fisier de tip bin incepand de la pozitia curenta a pointerului. Prototipul functiei este:
1 2 3 4 5 | uint FileWriteInteger( int file_handle // referinta fisierului int ivalue, // Valoare pe care dorim sa o scriem int size=INT_VALUE // Marimea in bytes ); |
Parametrii functiei sunt : referinta fisierului , file_handle , valoarea pe care dorim sa o scriem in fisier si marimea ei in bytes.
Untimul parametru poate fi 1, 2 sau 4. (1=char , 2=short , 4=integer).
Functia intoarce 1,2 sau 4 in functie de parametrul size si anume valoarea intoarsa trebuie sa fie egala cu acesta, daca functia s-a executat corect.
Exemplu de cod:
1 2 3 | int a=2; fh=FileOpen("test.bin",FILE_WRITE|FILE_BIN); s=FileWriteInteger(fh,a,4); |
Fisierul trebuie deschis ca bin neaparat , altfel functia da eroare. Daca functia a fost executata cu succes pointerul se muta cu cati bytes returneaza functia (1,2 sau 4).
Trebuie sa precizam ca prin 'int' in antetul functiei compilatorul intelege orice tip intreg, iar functia nu presupune intregi cu semn, putand lucra si cu intregi fara semn.
FileWriteLong()
Functia scrie o valoare long intr-un fisier bin incepand cu pozitia curenta a cursorului in fisier. Prototipul functiei este:
1 2 3 4 | uint FileWriteLong( int file_handle // Referinta fisierului long lvalue // Valoarea pe care dorim sa o scriem ); |
Parametrii functiei sunt : referinta fisierului intors de functia FileOpen() si valoarea pe care dorim sa o scriem.
Daca functia se executa cu succes intoarce 8 , lungimea in bytes a unei variabile de tip long.
Exemplu de cod:
1 2 3 | long a=212313123; fh=FileOpen("test.bin",FILE_WRITE|FILE_BIN); s=FileWriteLong(fh,a); |
FileWriteString()
Functia scrie un string intr-un fisier de tip txt sau bin incepand de la pozitia curenta a cursorului. Prototipul functiei este:
1 2 3 4 5 | uint FileWriteString( int file_handle // Referinta fisierului string svalue, // Stringul pe care doresc sa il scriu int size=-1 // Numarul de simboluri ); |
Parametrii functiei sunt: referinta fisierului , stringul pe care dorim sa il scriem si numarul de caractere pe care il contine stringul.
Al treilea parametru este obligatoriu in cazul in care fisierul a fost deschis cu FILE_BIN , dar optional cand fisierul a fost deschis ca FILE_TXT.
Daca executia functiei reuseste atunci rezultatul este numarul de bytes scris in fisier si pozitie cursorului se deplaseaza cu numarul de bytes scrisi in fisier.
De precizat ar fi ca atunci cand folosim functia pentru a scrie intr-un fisier deschis cu FILE_UNICODE (specificat sau nu, caci FILE_UNICODE e default) numarul de bytes scrisi este de 2 ori mai mare decat numarul de caractere. Cand scriem cu flagul FILE_ANSI numarul de bytes scrisi coincide cu numarul de caractere. E cel putin ciudata decizia MetaQuotes sa faca FILE_UNICODE default in loc de FILE_ANSI. Normal ar fi ca FILE_ANSI sa fie default, pentru a evita dublarea inutila a marimii fisierelor text, stiindu-se ca userii in marea majoritate le vor deschide cu Notepad sau Excel.
Exemplu de cod:
1 2 3 | string a="A1b2C3"; fh=FileOpen("test.txt",FILE_WRITE|FILE_ANSI); s=FileWriteString(fh,a); |
FileWriteStruct()
Functia scrie intr-un fisier de tip bin continutul unei structuri parsat ca un parametru incepand cu pozitia curenta a cursorului. Prototipul functiei este:
1 2 3 4 5 | uint FileWriteStruct( int file_handle // Referinta fisierului any_simple_struct str_object&, // Link catre obiectul de tip struct int size // Marimea care o sa fie scrisa in bytes ); |
Parametrii functiei sunt: referinta fisierului intoarsa de functia FileOpen() , variabila de tip structura (trimisa prin referinta) si marimea in bytes pe care dorim sa o scriem. Daca functia este executata cu succes returneaza numarul de bytes scris.
Exemplu de cod:
1 2 3 4 5 | MqlRates a[1]; CopyRates(Symbol(),PERIOD_D1,0,1,a); int so=sizeof(a); fh=FileOpen("te.bin",FILE_WRITE|FILE_BIN); s=FileWriteStruct(fh,a,so); |
Cand definim structura 'a' trebuie sa o definesc ca pe un tablou , ca sa pot sa scriu in structura cu functia CopyRates() si trebuie neaparat sa o definesc ca avand cel putin un element.
De precizat ca in fisierele deschise cu FILE_BIN in care am scris ceva daca le deschidem o sa vedem niste caractere ciudate. Sa nu credeti ca valoarea pe care am vrut sa o scriem a fost scrisa gresit. Desi fisierele sunt bin le-am salvat ca fiind '.txt' pentru a putea sa le deschideti usor cu editorul text si sa vedeti ca ceva s-a fost scris.
Se pare ca MetaQuotes a ales o cale complicata pentru fisiere. Voi face o scurta trecere in revista a felului in care Borland Pascal cunostea fisierele, doar ca sa vedeti ce simplu era la vremea aceea (anii '90).
Mai intai, Borland Pascal nu avea conceptul de referinta de fisier , de numar care sa il identifice. Avea doar variabile de tip fisier. Acestea erau variabile complexe, cunoscute doar de compilator - nu se puteau citi, scrie sau interoga. Functiile de citire/scriere erau cam 6 la numar , si anume: ReadLn, WriteLn, Read, Write, BlockRead, BlockWrite. ReadLn si WriteLn lucrau doar cu ecranul, tastatura si fisierele text, in vreme ce Read si Write lucrau si la nivel "binar". Datorita naturii speciale a variabilelor fisier, Read si Write stiau daca au operatiune I/O cu tastatura/ecranul sau cu un fisier. Nu era nevoie de FileRead sau FileWrite, intrucat daca primul parametru era o variabila fisier, el nu putea fi luat drept integer sau altceva - functiile stiau din start cu ce lucrau. Daca era file of text , si scriai Write(f,128) , functia ar fi scris "128" , text , pe 3 caractere, iar daca era file of byte, functia ar fi scris un byte cu valoarea 128.
De asemenea, definirea stricta a variabilelor facea diferenta dintre tipurile de variabile si functiile stiau din start cati bytes au de citit/scris pentru fiecare tip de date. Daca fisierul avea un tip complex, gen file of record (record era echivalentul struct din MQL5), atunci functiile citeau si scriau una sau mai multe structuri la rand, incrementand pozitia in fisier cu numarul de structuri, nu cu numarul de bytes. BlockRead si BlockWrite lucrau cu orice fel de variabile, fiind interesate numai in lungimea blocurilor citite/scrise (functionau pe fisiere fara tip).
Multa atentie cand folositi functiile de fisiere. Altfel, puteti pierde timp inregistrand date care sunt salvate gresit in fisiere!