preview
Do básico ao intermediário: FileSave e FileLoad

Do básico ao intermediário: FileSave e FileLoad

MetaTrader 5Exemplos |
31 0
CODE X
CODE X

Introdução

No artigo anterior Do básico ao intermediário: SandBox e o MetaTrader, foi explicado da maneira o mais simples e prática que foi possível ser pensada. O que seria uma SandBox e como ela influencia nossas atividades no MetaTrader 5. Isto quando estamos focados em trabalhar com as funções e procedimentos presentes na biblioteca do MQL5, a fim de criar, manipular e efetuar leituras em arquivos de maneira geral.

Porém aquele conteúdo visava apenas e tal somente, explicar o que seria a SandBox. Não sendo de fato os melhores meios ou mecanismos para se trabalhar com arquivos. Já que existem maneiras bem melhores de se fazer isto, usando para isto MQL5 puro. Sem necessidade de utilizar alguma função do sistema operacional.

Ok, acreditando que você, meu caro leitor, conseguiu compreender o que seria uma SandBox e como ela afeta a nossa vida. Podemos começar a pensar em trabalhar com arquivos, visando obter outros tipos de resultados. Lembrando que aqui, não estaremos focados em criar nenhuma aplicação em especial. Apenas iremos utilizar algumas das funções e procedimentos presentes na biblioteca do MQL5, para demonstrar como certas atividades poderiam ser implementadas. De qualquer maneira é necessário que você se dedique a praticar o que será visto aqui, a fim de entender alguns detalhes que por ventura você ficar com dúvidas sobre os mesmos. Então como é de costume, vamos a um novo tópico para começar a entender certas coisas.


Não existe receita de bolo

No artigo anterior, fizemos uma implementação de leitura e escrita, com um objetivo bastante simples. E que naquele momento, poderia ser deixado da forma como estava sendo executado. Porém, na prática e na hora do vamos ver, as coisas nem sempre são implementadas como foi mostrado ali. Isto devido a um problema que pode vir a ocorrer. Para refrescar a sua memória, vamos rever que tipo de problema é este do qual acabamos de mencionar. Para isto, vamos usar um dos códigos vistos no artigo anterior. Este pode ser visualizado logo abaixo.

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. //+------------------------------------------------------------------+

Código 01

Quando este código 01 é executado, ele irá gerar um arquivo, cujo conteúdo é visto na imagem logo na sequência.

Imagem 01

Nesta imagem 01 estou apontando para um símbolo estranho. Que no caso seria um caractere nulo. Este é usado para definir o limite de uma string. Não sendo de fato um problema, dentro do contexto da aplicação que esteja utilizando este tipo de modelagem de strings. Porém, em um arquivo, cujo objetivo, seria o de conter texto puro. A presença de tal caractere não faz nenhum tipo de sentido. Sendo muitas das vezes, um problema dependendo do objetivo, ou destinação do arquivo de texto.

Existem diversas formas diferentes de se resolver este tipo de inconveniente. Algumas são mais diretas, enquanto outras indiretas, precisando utilizar alguns passos extras para serem corretamente implementadas. Pois bem, apesar disto, existe uma outra questão sobre este código 01. Apesar da linha onze ser capaz de criar um arquivo e salvar dados diretamente nele de forma muito simples e direta. Esta maneira de resolver as coisas, nos traz um outro problema, que iremos abordar de maneira mais profunda em breve. Que é justamente um acesso aleatório aos dados presentes no arquivo.

Apesar de parecer estranho falar isto, arquivos de disco, na prática não são sistema de leitura sequencial. Como acontece em caso de arquivos em unidades de fita, por exemplo. Ali, quando precisamos ler um arquivo, ou alguma informação, precisamos ler uma boa parte da fita magnética. O que tornar o processo de leitura e escrita um tanto quanto complicado em alguns momentos. Porém, quando isto é feito em arquivos armazenados em disco, podemos ter tanto um acesso sequencial, como também um acesso randômico. Onde podemos ler ou escrever, qualquer trecho do arquivo a qualquer momento.

No entanto, apesar disto poder ser feito, esta função FileSave, assim como FileLoad, não são funções adequadas para acesso randômico. Já que as mesmas gravam ou fazem a leitura de um bloco inteiro do arquivo. Onde normalmente este bloco, terá o arquivo inteiro sendo carregados ou salvo em disco. Para pequenos arquivos, isto não é problema, e se o conteúdo do arquivo, puder ser ignorado, a fim de ser sobre gravado, podemos utilizar FileSave e FileLoad, sem nenhum problema em nossas aplicações. Já que são uma maneira muito prática e segura de ler e gravar arquivos.

Porém, toda via e, entretanto, a ideia é modificar o arquivo, mantendo parte de seu conteúdo intacto. Usar FileSave e FileLoad, talvez possa não vir a ser a melhor solução. Uma vez que precisamos manter todo o arquivo em memória. O que pode vir a ser algo um tanto quanto desnecessário. Já que muitas vezes, precisamos apenas manter um pequeno fragmento, no qual estamos trabalhando em memória. O resto pode ficar em disco, e ser carregado quanto assim vier a ser necessário.

Por isto, não existe uma receita de bolo. Ou uma forma geral e definitiva de se fazer as coisas. Cada caso é um caso, e a solução a ser adotada, deve ser pensando com base no tipo de critério que precisa ser obedecido. Isto a fim de tornar o uso do próprio MetaTrader 5, algo agradável e prático, por parte do usuário de suas aplicações.

Para tornar as coisas que foram ditas a pouco, um tanto quanto mais simples de entender e ao mesmo tempo mais plausíveis. Vamos criar alguns exemplos simples para que você, meu caro leitor, consiga entender onde estamos querendo chegar, ao falarmos que cada implementação precisa ser pensada de maneira individual. Já que muitos de vocês, podem não vir a ter a devida noção do quanto certas decisões podem e irão influenciar a forma como uma aplicação será e deverá ser implementada.

Vamos começar tentando adicionar uma nova informação a um arquivo que já esteja salvo em disco. No caso, o arquivo no qual iremos manipular, será exatamente o mesmo que o código 01 estará criando. Mas este mesmo código 01 sofrerá algumas mudanças a fim de promover o que está manipulação do arquivo. Lembre-se: O objetivo é adicionar novas informações no arquivo, já salvo. Bem, em teoria, você pensaria em fazer algo parecido com o que é visto logo abaixo.

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. //+------------------------------------------------------------------+

Código 02

Ao executar este código 02, você espera que tenhamos no arquivo Hello.txt, o conteúdo visto na imagem 01, e também uma nova informação. Bem, as informações que deveriam estar no arquivo, são vistas nas linhas seis e sete deste código 02. Note que se trata de algo muito simples de entender. No entanto, ao executar este script no MetaTrader 5, o resultado não é exatamente como o esperado. E este pode ser visualizado logo abaixo.

Imagem 02

Pois bem, agora vem a grande pergunta, junto com uma dúvida igualmente crucial. O que aconteceu aqui, para que o resultado fosse este que podemos ver na imagem 02? Isto por que não seria de fato este o resultado esperado. Já que a princípio, tanto o conteúdo da linha seis, quanto o conteúdo da linha sete, deveria aparecer no que seria o conteúdo final, presente no arquivo. No entanto, somente a mensagem presente na linha sete é que está sendo mostrada.

Ou vendo de uma outra maneira: Por algum motivo, o conteúdo da linha seis está sendo ignorado, e apenas o conteúdo da linha sete está sendo usado. Então, o que está acontecendo com o conteúdo da linha seis? Este é um dos problemas, mais complicados, para se entender, sem o auxílio de alguém que realmente venha a lhe explicar o que está acontecendo aqui. Mas na prática, é algo bem simples. Quando executamos a linha seis, a função da linha quinze irá gravar os dados no arquivo. Logo depois, quando executamos a linha sete. Aquele mesmo arquivo será destruído e um novo conteúdo será gravado nele. De fato, apesar de ser simples de entender, sem que alguém lhe explique isto, fica difícil encontrar um motivo para que o código, não grave certas informações. Dando assim a impressão de que nosso código está com um grave erro. Quando na verdade, o problema é outro.

Ok, mas como poderíamos resolver este problema? Isto a fim de conseguir armazenar ambos conteúdos, tanto da linha seis, quanto da linha sete no mesmo arquivo. Bem, meu caro leitor, como o título deste tópico diz: NÃO EXISTE RECEITA DE BOLO. Existem diferentes propostas para se resolver isto. E cada uma tem vantagens e desvantagens. Aqui irei mostrar uma apenas para fins de demonstração. Mas você pode pensar em outras, e tentar implementar as mesmas. Mas procure fazer isto, usando como base a função FileSave. Isto por que, existem outras soluções que são bem mais simples, se forem bem elaboradas.

Mas vamos ver o que seria uma primeira solução. Esta pode ser vista logo abaixo.

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. //+------------------------------------------------------------------+

Código 03

Ao executar este código 03, você terá como resultado algo muito parecido com o que é visto na imagem logo abaixo.

Imagem 03

Pois bem, o resultado agora é exatamente como seria esperado. Ou seja, tanto o conteúdo da linha seis, quanto o conteúdo da linha sete, estão sendo adicionados ao arquivo. Porém, não é somente isto. Você pode notar que agora não temos mais aquele caractere NULL sendo adicionado. Como foi possível resolver dois problemas de uma só vez?

E mais, se você olhar e pensar com um pouco de calma, irá acabar notando que este procedimento SaveInfo visto na linha dez do código 03. Seria praticamente o código de criação de arquivos de log. Ou seja, sem muito trabalho e custo, você pode criar um sistema para checar em arquivo, coisas que seu código esteja fazendo. Isto a fim de entender e estudar com calma o que está se passando durante a execução. Legal não é mesmo? Algo simples de ser implementado, e com um resultado e possibilidades bem interessantes.

Mas vamos entender o que aconteceu aqui, para que fosse possível corrigir o código 02, a fim de tornar este código 03 muito mais adequado. Mas principalmente capaz de salvar tanto o conteúdo da linha seis como também o conteúdo da linha sete.

Para isto, você pode notar, que adicionei uma constante. Isto a fim de ter um acesso comum ao arquivo. Já que na linha 15 estaremos lendo o mesmo e na linha 18 estaremos gravando o arquivo. Mas por que fazer isto? Bem, meu caro leitor, o motivo é que, como você viu no código 02. FileSave irá salvar o conteúdo do buffer em uma única passada. Ou seja, se o buffer, que no caso seria o nosso arrray info, contiver uma dada informação, esta informação irá sobre gravar a informação original do arquivo. No entanto, quando efetuamos a leitura do arquivo, carregamos o conteúdo do mesmo para dentro do buffer. E logo depois usando a linha 17, adicionamos o que seria a nova informação, ao que já existia no buffer original do arquivo. Seria como se estivéssemos literalmente, criando o arquivo na memória, para somente depois o armazenar em disco.

Este tipo de operação, para este exemplo que estamos utilizando, é muito rápida. Porém, conforme o arquivo vai crescendo, isto acaba se tornando um problema. Já que esta leitura e escrita, feitas desta forma, acabam por tornar sua aplicação menos eficiente em termos de uso dos recursos da máquina. E isto acaba influenciando no tempo de execução. Já que quanto mais dados estão presentes no arquivo, maior será o tempo gasto para ler e gravar os dados no disco. Mas para casos simples, como este que estamos abordando aqui. Este tipo de solução pode ser adotada.

Legal, mas o que acontece se executarmos a aplicação novamente? Já que à primeira vista ela está funcionando sem nenhum tipo de problema. Bem, neste caso, teremos as linhas seis e sete sendo gravadas novamente e novamente. Sempre adicionando, mais e mais linhas com a mesma informação. Isto até que você venha a apagar o arquivo original, para que todo o processo se inicie novamente do zero. Ou seja, temos um novo trabalho a ser feito. E este pode ser feito, via código, basicamente de duas maneiras diferentes. Apesar de existirem mais maneira, vamos focar apenas em duas aqui.


Primeira forma de solução

A primeira maneira de se resolver isto, seria deletando o arquivo, e começando a reescrever o mesmo conforme a aplicação for sendo executada. Para fazer isto, precisaremos mudar o código 03 para algo como o que é visto logo abaixo.

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. //+------------------------------------------------------------------+

Código 04

Muito bem, este código 04 resolve em parte o nosso problema, que existia no código 03. Porém é importante ressaltar que esta solução, apesar de funcionar é um tanto quanto perigosa. Isto por que, se por ventura, você, como programador se esquecer de indicar a SandBox correta, poderá acabar criando uma baita de uma confusão. E o motivo é que esta linha oito vista no código 04, de fato irá deletar o arquivo indicado. Porém, se a leitura que é feita na linha 17 e a gravação que é feita na linha 20, estiverem em desacordo com esta linha oito. E isto no que se refere a qual SandBox que esteja sendo utilizada. Poderemos estar deletando um arquivo que não seria exatamente aquele pretendido.

Como este código 04 estará no anexo, você poderá modificar o mesmo, de forma a tentar entender que tipo de problema pode vir a existir, caso estejamos utilizando SandBox diferentes. Porém para resolver este problema, você pode adicionar uma definição a fim de sincronizar todos os aspectos da implementação. Evitando assim problemas de estar utilizando uma SandBox diferente em momentos distintos. Isto pode ser feito como visto logo abaixo.

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. //+------------------------------------------------------------------+

Código 05

Note que aqui neste código 05, resolvemos o problema de sincronização de uma forma muito prática. Apenas pelo simples fato de termos definido a linha cinco e a utilizado de modo a selecionar qual código deveria ser compilado. Isto evita que venhamos a ter diversos problemas relacionados ao fato de estarmos tentando acessar um arquivo em um ponto e o acessando de outra forma em outro ponto.

Ok, parece que demos uma boa guinada no código. Mas se você vem estudando e procurando praticar o que tem sido mostrado nestes artigos. Deve ter pensado o seguinte: Será que não existiria uma forma de colocar esta chamada a FileDelete dentro do procedimento SaveInfo? Isto evitaria de que precisássemos utilizar esta implementação vista no código 05, ao mesmo tempo que mantemos uma certa sincronização da própria SandBox. Já que todas as funções de biblioteca estariam todas reunidas, nos permitindo uma mudança mais fácil e ativa do código.

Sim, meu caro leitor, existe uma forma de fazer isto. Apesar de não ser uma maneira muito convencional, ela de fato funciona. A forma de se fazer isto, com base no que foi mostrado até neste momento, seria utilizando uma variável estática. Uma forma mais segura, seria o uso de classes, mas como ainda não entramos neste conceito, não irei mostrar como implementar a solução via classe. Mas posso mostrar a solução usando uma variável estática. E esta é feita utilizando o código logo abaixo.

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. //+------------------------------------------------------------------+

Código 06

Agora preste atenção meu caro leitor. Apesar de este código 06 ser muito similar ao código 04. Este código 06 tem um comportamento bem diferente. Isto por conta justamente da variável estática declarada na linha quinze. Mas o fato de termos concentrado, todas operações a serem feita no arquivo, em um único lugar, que seria justamente o procedimento SaveInfo. Torna muito mais simples, procurarmos e modificarmos as coisas conforme a necessidade que estivermos tendo. Já que não precisaremos ficar procurando no código, pontos que podem estar conflitando como as operações esperadas no arquivo.

Ok, acredito que deva ter dado para entender como poderíamos trabalhar com o sistema, deletando o arquivo original. Porém podemos fazer um pouco diferente, e ainda assim obter o mesmo tipo de resultado conseguido com as mudanças feitas e mostradas neste tópico. Para mostrar isto, vamos a um novo tópico, onde irei mostrar o que seria o segundo tipo de solução.


Segunda forma de solução

Como foi dito, anteriormente, existem mais formas de se resolver o problema. Porém, aqui irei abordar apenas duas para que você não fique apegado a uma única solução. Pensar em formas de solucionar problemas é o trabalho de todo bom programador. Então vamos ver o que seria a segunda forma de solucionar o problema. E você irá se surpreender com o nível de simplicidade adotada. Para ser sincero, a solução seria algo entre o código 03 e o código 06. Porém, para que as coisas venham a fazer sentido. Gostaria que você pensasse na solução que será vista aqui, como sendo algo pertinente ao código 03 depois de uma simples mudança. E esta mudança pode ser vista logo na sequência.

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. //+------------------------------------------------------------------+

Código 07

Agora olhe para este código 07 e responda sinceramente. Você está conseguindo entender o que está acontecendo ali? Note que o código em si se parece em muito com um misto entre o código 03 e o código 06. Porém, diferente do código 06, onde usávamos a função FileDelete. Aqui, neste código 07, estamos usando o próprio sistema de gravação para limpar o arquivo, ao mesmo tempo que garantimos que ele receba novas informações conforme elas forem chegando. Mas como isto foi conseguido?

Bem, meu caro leitor, se você está na dúvida de como isto foi possível, talvez devesse dar uma estudada nos primeiros artigos desta série. Onde expliquei como trabalhar com variáveis estáticas. Apesar de muitos considerarem variáveis estáticas um tema complicado, entender elas, é primordial para se conseguir solucionar diversos problemas de maneira simples e sem muita complicação. Tornando o código algo bastante portável entre aplicações diferentes, mas com um mesmo objetivo.

O artigo onde expliquei sobre variáveis estáticas é Do básico ao intermediário: Variáveis (II). Como este código 07 é muito simples de entender, se você entender os conceitos envolvidos no que está sendo usado ali. Não vou desperdiçar tempo explicando como ele funciona. Ao invés disto, vamos ver uma outra solução, muito parecida. Porém com um tipo de resultado bem interessante, e que merece e pode ser explicado aqui.

Em todos estes códigos, vistos até aqui, você pode ter notado que estávamos sempre e sempre atrelados a um único arquivo. Que estava sendo definido em algum ponto do código. Muitos de vocês, podem até mesmo imaginar que seria muito bom se pudéssemos salvar as coisas em arquivos diferentes. E isto sem precisar mudar em absolutamente em nada o código.

Bem, na grande parte das vezes, você poderia simplesmente pensar em uma forma de passar o nome do arquivo a ser salvo como sendo um argumento para o procedimento SaveInfo. Bem, isto seria uma forma de resolver o problema, mas ao mesmo tempo isto iria gerar outros tipos de problemas. Que podem vir a ser mais ou menos complicados de serem resolvidos. Dependendo é claro do tipo de atividade esperada e requerida por sua aplicação. No entanto, existe uma forma, relativamente elegante de se resolver esta questão, onde podemos salvar as coisas em arquivos diferentes e sem muito trabalho.

Esta forma envolve programação estruturadas. Já falamos sobre isto em um pequeno bloco de artigos dentro desta mesma sequência atual. E como se trata de um tema, que foi tratado em mais de um artigo, não irei, neste caso direcionar um link para você. Já que talvez você necessite ver o tema desde o começo para entender de maneira correta, como a programação estrutural realmente acontece. Entretanto, não é justo para aqueles que vem acompanhando os artigos, e estudando o que vem sendo mostrado. Que não mostremos como resolver esta questão, sobre a forma de selecionar o nome do arquivo a ser salvo.

Então para aqueles que já entendem os conceitos básicos sobre a programação estruturada, vamos ver como seria o código, para que tenhamos uma solução bem melhor do que a vista até aqui. Mas que também necessite de poucos acessos ao disco, como é feito no código 07. Esta solução é mostrada logo abaixo.

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. //+------------------------------------------------------------------+

Código 08

Este código 08 é muito divertido, além de ser bastante interessante. Já que ele aplica diversos conceitos ao mesmo tempo. Isto para que tenhamos um tipo muito especifico de coisa sendo feita. Como muitos de vocês, mesmo os que procuraram estudar os artigos em que expliquei como a programação estruturada acontece, podem ficar na dúvida sobre como este código funciona em alguns pontos. Vou dar uma rápida explicação sobre alguns pontos de interesse. Porém notem que grande parte do código, se parece em muitos aspectos, com o código 07. Só que aqui estamos fazendo algo um pouco mais elaborado. E por consequência bem melhor, pelo menos ao meu entender.

Note que na linha quatro, estamos declarando uma estrutura. Esta servirá de base de apoio para o que iremos fazer. Dentro dela temos algumas variáveis privativas, e dois procedimentos. O procedimento da linha 12, tem como objetivo, informar qual o nome do arquivo em que estaremos trabalhando em um dado momento. Além é claro, nos permitir mudar a SandBox que estivermos utilizando. Beleza, agora vem a parte um pouco complicada neste primeiro momento.

Como estamos trabalhando com um código estrutural e não com uma classe. Não temos como fazer certos tipos de coisas. Mas temos como fazer outras. No caso, quando o compilador cria o mecanismo para que a região da memória seja alocada para as variáveis, que estão sendo declaradas entre as linhas sete e nove. Ele também promove uma pre inicialização dos valores. Saber que tipo de valor inicial teremos nesta região da memória é muito importante. Geralmente string são inicializadas como nulas. Isto nos garante uma forma de se fazer o teste visto na linha 23.

Este teste tem como objetivo, garantir que tenhamos algum arquivo sendo apontado. Ou seja, caso não tenhamos indicado um arquivo a ser utilizado, este teste irá ter sucesso, fazendo com que o procedimento SaveInfo retorne imediatamente. O resto do código é bem simples de entender. Já que foi visto em outras partes aqui, neste artigo.

No entanto, vamos para o procedimento OnStart, pois ali é necessário dar uma certa explicação, a fim de que você possa saber como estudar de maneira adequada este código 08.

Observe que na linha 39 estamos criando uma variável para poder utilizar a estrutura definida na linha quatro. Agora, quando a linha 41 vier a ser executada, iremos estar dizendo qual será o arquivo que estaremos utilizando a partir daquele momento. Preste atenção a isto, meu caro leitor. Sem a existência desta linha 41, as próximas chamadas não teriam nenhum tipo de efeito prático.

Mas a parte curiosa vem justamente na linha 45. Neste momento, estaremos modificando o fluxo de informações que antes era direcionado a um arquivo, que foi definido na linha 41, para um outro arquivo. Mas não é somente isto. Observe que apesar dos pesares, o nome do arquivo é o mesmo que foi definido na linha 41. No entanto, aqui estamos mandando que o MetaTrader 5, direcione o fluxo para uma outra SandBox.

Mas podemos fazer isto? Sim, meu caro leitor. Note que independentemente de como o código precise, ou venha a ser implementado. Podemos direcionar as coisas de uma maneira super simples para qualquer arquivo no qual tenhamos algum tipo de acesso. Isto desde que possamos escrever na SandBox indicada.

Na prática, a coisa é bem mais interessante do que aparente ser, apenas olhando este código. Tanto que quando você executar este código 08, irá ter como resultado a criação de dois arquivos. Ambos podem ser vistos logo abaixo.

Imagem 04

Imagem 05

Observe que o conteúdo é diferente. Assim como também o diretório, que está sendo destacado em verde.


Considerações finais

Neste artigo, vimos que não existe uma receita de bolo para se trabalhar com sistemas de arquivos. Começamos a colocar em prática algo que muitos podem achar complicado de ser feito, mas com o tempo, estudo e dedicação, você acabará pegando gosto e jeito para a coisa. Não existe uma solução mágica. O que existe de fato é a aplicação de diversos conceitos, de tal forma que no final podemos ter um determinado resultado.

Então meu caro leitor, procure estudar e praticar o que foi visto aqui. Pois o correto entendimento aliado a uma prática constante e sempre buscando novas formas de se fazer a mesma coisa, é que irão lhe dar o conhecimento adequado. No anexo, você terá os códigos, para poder estudar e praticar o que foi mostrado aqui. Porém, não use apenas as coisas como estão no anexo. Procure mexer nos códigos, principalmente neste código 08, a fim de entender melhor como as linhas 41 e 45 afetam o resultado geral do que estará sendo feito. Pois no futuro, quando as classes já tiverem sido explicadas, você irá ver que este código 08, tem grandes possibilidades de melhorias e facilidade de uso, desde que você o adeque da maneira correta. Mas para fazer isto, primeiro é necessário, você entender como este código estrutural funciona

Arquivo MQ5Descrição
Code 01
 Demonstração de acesso a arquivo
Code 02  Demonstração de acesso a arquivo 
Code 03  Demonstração de acesso a arquivo
Code 04  Demonstração de acesso a arquivo
Code 05  Demonstração de acesso a arquivo
Code 06  Demonstração de acesso a arquivo
Code 07  Demonstração de acesso a arquivo
Arquivos anexados |
Anexo.zip (3.58 KB)
Simulação de mercado: Position View (IV) Simulação de mercado: Position View (IV)
Aqui começaremos a unir diversas coisas, ou aplicações que antes estavam complemente isoladas entre si. Apesar de que o Chart Trade, o Indicador de Mouse e o Expert Advisor, já terem algum tipo de relacionamento. Não havia ainda uma forma de podermos observar, posições que estivessem abertas no servidor de negociação, isto diretamente no gráfico. Fazendo muitas das vezes uso de um sistema cross order. Mas a partir deste momento isto começa a se tornar possível. Abrindo diversas portas para novas ideias e implementações futuras. Se bem que estamos apenas começando a fazer as coisas acontecerem. Mas já teremos uma direção na qual seguir.
Criando um painel administrativo de negociação em MQL5 (Parte III): Expansão das classes incorporadas para gerenciamento de temas (II) Criando um painel administrativo de negociação em MQL5 (Parte III): Expansão das classes incorporadas para gerenciamento de temas (II)
Vamos expandir a biblioteca existente Dialog, incorporando nela a lógica de gerenciamento de temas. Além disso, vamos integrar os métodos de troca de temas nas classes CDialog, CEdit e CButton, utilizadas no nosso projeto de painel administrativo.
Criação de um EA em MQL5 com base na estratégia PIRANHA utilizando Bandas de Bollinger Criação de um EA em MQL5 com base na estratégia PIRANHA utilizando Bandas de Bollinger
Neste artigo, criamos um EA (Expert Advisor) em MQL5 com base na estratégia PIRANHA, utilizando as Bandas de Bollinger para aumentar a eficiência da negociação. Discutimos os princípios-chave da estratégia, a implementação do código, bem como os métodos de teste e otimização. Esse conhecimento permitirá usar o EA com eficácia em seus cenários de trading.
Título no Connexus (Parte 3): dominando o uso de cabeçalhos HTTP em requisições Título no Connexus (Parte 3): dominando o uso de cabeçalhos HTTP em requisições
Continuamos o desenvolvimento da biblioteca Connexus. Neste capítulo, exploraremos o conceito de cabeçalhos no protocolo HTTP, explicando o que são, para que servem e como utilizá-los nas requisições. Analisaremos os principais cabeçalhos utilizados ao interagir com APIs e apresentaremos exemplos práticos de como configurá-los na biblioteca.