TFileStream – Técnicas Avançadas – Parte II


Olá desenvolvedores Delphi, vamos nesta nossa continuação explicar mais detalhes pra finalizar nosso maravilhoso projeto de leitura de arquivos de tamanho gigantes com técnicas avançadas de TFileStream!

O propósito destes dois artigos é implementar através de um objeto de TFileStream o carregamento, leitura e alteração (escrita) de arquivos de modo texto de qualquer tamanho, realizando também operações de procura neles. O interessante é que podemos carregar tudo em um objeto como um descendente de TListView em modo virtual, cujas linhas do arquivo carregado são lidas em modo de execução (o programa não sabe o que vai ler até que a solicitação da linha seja indicada como este parâmetro) e que todas estas linhas são armazenadas em um objeto da classe TInt64List, que é uma classe que implementa um array de Int64, ou seja, armazena todos os offsets (bytes das posições encontradas – cada posição que encontra o caracter  “quebra de linha” #10 – linefeed) que são todas as linhas encontradas. Resumindo, o programa solicita um número de linha pra ler -> o programa verifica se esta linha está inserida no objeto da classe TInt64List, se tiver, retorna a posição do byte em que encontra esta linha (offset) -> uma função do nosso programa irá ler a partir deste offset até encontrar o próximo caracter  “quebra de linha” ou então o caracter de fim de arquivo. Se não estiver neste objeto de TInt64List, então nada será retornado pois não há a linha cadastrada neste array pra ser exibido.

Meus testes aqui foram realizados com 8GB de memória RAM e processador iCore5. Como era pra testar, então resolvi carregar um arquivo bem grande pra dentro do nosso programa – um arquivo de 12 GB. Os testes foram incríveis, em dois minutos e meio ele foi carregado com sucesso pra dentro do programa. Vamos ver as telas e o quadro comparativo abaixo:

 


1 – Tela de informação exibindo que o arquivo de 12GB (“c3.log”) foi carregado com sucesso.
 

 

2 – Tela principal do aplicativo, com o arquivo carregado de 12 GB em 2 min e 36 seg.
 

 


3 - Tela principal do arquivo – exibindo o final do arquivo de 12GB.
 

 


4 – Tela de edição do arquivo, editando a última linha do arquivo de 12GB (alterando a string da linha “FIM DO ARQUIVO !!” para “END OF FILE”.
 



5 – Linha alterada do arquivo de 12GB pra “END OF FILE”.



6 – Arquivo carregado novamente, depois de ter sido finalizada sua edição, exibindo como última linha a string “END OF FILE” no lugar daquela “FIM DO ARQUIVO !!” de antes. Quadro comparativo de arquivos, funcionalidades e tempo processado (obs: tempo aproximado).

 


Tamanho

Leitura

Início da Edição

Finalização da Edição

Procura

Procura e Substituição

12 GB

2:36 min

8:02 min

6:09 min

5:56 min

4:19 min

6 GB

1:24 min

5:08 min

3:15 min

4:06 min

4:48 min

2 GB

11 seg

26 seg

33 seg

52 seg

1:15 min

1 GB

8 seg

8 seg

16 seg

42 seg

45 seg

25 MB

404 milesimos seg

44 milesimos seg

110 milesimos seg

6 seg

1 seg

 

Com o quadro acima podemos perceber que quanto maior for o arquivo maior o tempo pra realizar suas operações. Mas o tempo gasto não chega a ser entediante nem pesado pra ler e visualizar um arquivo gigantesco de 12 GB, por exemplo. Hoje em dia muitas aplicações “travam” pra fazer um processamento semelhante pra ler um arquivo com muito menos tamanho que isso – já presenciei aplicações pra ler tamanho de arquivos de 50 MB quase que estourando a memória, levando vários e vários minutos pra realizar este processamento – por isso foi a principal razão de eu querer desenvolver este projeto, pra contribuir principalmente com a comunidade de desenvolvedores através deste aplicativo com esta eficiência de processamento, pra ler e editar arquivos de tamanho ilimitado – algo indisponível na internet!
Processo de divisão por partes.

O processo de edição de arquivos compreende em dividir o arquivo em várias partes. O programa vai dividir um arquivo em várias partes aproximadas de 24414 MB até totalizar todo o arquivo. Isso será feito no mesmo diretório onde se reside o arquivo; será criado um subdiretório com o nome deste, e dentro dele estarão todos os seus arquivos divididos. O programa gerenciará todos estes arquivos divididos temporários dentro de si, exibindo um a um e podendo ser editados, parte a parte, de dentro do programa. Mais ainda, o programa contará com um suporte de localização de palavras pra filtrar todas as ocorrências dos arquivos encontrados com elas. Então, pra recapitular, o nosso programa vai dividir o arquivo original. As partes estimadas de divisão seguirão sempre à mesma fórmula: total de partes aproximadas de divisão => corresponde ao tamanho do arquivo original (em bytes) / 25000000 bytes (25000000/1024 => 24414,0625 MB).

Um arquivo inferior ao valor de 24 MB sempre resultará em apenas uma parte a ser dividida. Outra questão são requisitos essenciais pra funcionar, como permissão e espaço no diretório a ser utilizado pelo programa – senão este processo não irá funcionar, bem como obviamente a memória disponível do computador e a quantidade de programas executando no momento da execução do programa – tudo isso pode interferir negativamente no nosso programa. É claro que quanto mais memória tiver e mais rápido o processador for, os resultados tendem a ser melhores, ou seja, mais rápidos – o tempo de resposta será mais rápido.


Outras telas:

 



7 – Tela de pesquisa de palavras (observe o painel inferior esquerdo; um objeto de TListBox contendo as palavras pesquisadas com sucesso juntamente com as linhas onde foram encontradas).
 



8 –  Tela de edição de arquivos, exibindo todas as partes e seus conteúdos associados.

 

Conclusão

 

Vimos uma nova estratégia e uma nova abordagem, de como ler arquivos gigantes e também de como editar estes arquivos gigantes. Os arquivos nunca serão carregados de uma vez no programa, porque pra ler ele usufruímos de componentes renderizados em modo virtual, onde não são proprietários de seus dados, ficando a cargo de uma estrutura baseada em vetores em memória pra agilizar esta operação, onde estes vetores armazenam as linhas e offsets das posições de todos os caracteres de “line feed” (quebra de linha) de todas as linhas, por sua vez apontando pro arquivo a ser lido este parâmetro da linha a ser pesquisada, retornando finalmente a frase encontrada até chegar ao próximo caracter de quebra de linha ou ao fim do arquivo. Funcionando assim o processamento de leitura é significadamente reduzido; arquivos na casa dos

GB serão visualizados bem rapidamente e sem onerar o processamento da sua aplicação!

Pra alterar um arquivo, outra abordagem será feita; o arquivo é subdividido em partes, onde todas as partes totalizam o arquivo em si, e o usuário poderá escolher a parte que quer alterar, abrindo ela e editando o conteúdo desejado, abrindo outra parte, etc; e também poderá pesquisar alguma string em todas estas partes, através de uma rotina multi-thread pra este propósito – tudo isso pra satisfazer a eficiência de uma resposta com qualidade.

Portanto, esta foi a última parte da implementação deste projeto, abordando todos os itens de leitura, edição, procura e procura com alteração de conteúdos, tudo baseado pela classe TFileStream pra empregar estas funcionalidades.

Bons estudos com este projeto, totalmente free e disponíveis a todos os desenvolvedores Delphi!

 

Sobre o Autor

Hamden Vogel , Consultor TheClub

E-mail: suporte@theclub.com.br

The Club - O Maior Clube de programadores do Brasil