sábado, 13 de outubro de 2012

Tratando arquivos textos via TFileStream

Trabalhar com arquivos textos no Lazarus é bem fácil. Há várias maneiras de se tratar arquivos textos, desde o velho modo do Pascal (AssignFile/Reset/Rewrite/Append/CloseFile) aos métodos (LoadFromFile/SaveToFile) dos descendentes de TStrings. Mas para trabalhar com arquivos grandes é mais eficiente usar TFileStream.

Para demonstrar o uso do TFileStream montei um pequeno exemplo no Lazarus, como mostra a imagem abaixo.


O código do projeto acima encontra-se a seguir.

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Memo1: TMemo;
ButtonAbrir: TButton;
ButtonSalvar: TButton;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
procedure ButtonAbrirClick(Sender: TObject);
procedure ButtonSalvarClick(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.ButtonAbrirClick(Sender: TObject);
var
Buf: Byte;
Linha: String;
FileStreamTxt: TFileStream;
begin
if OpenDialog1.Execute then
try
FileStreamTxt := TFileStream.Create(OpenDialog1.FileName, fmOpenRead or fmShareDenyNone);
Linha := '';
Memo1.Clear;
while (FileStreamTxt.Position <= FileStreamTxt.Size - 1) do begin
FileStreamTxt.Read(Buf, 1);
Linha := Linha + Chr(Buf);
if (Pos(LineEnding, Linha) > 0) or (FileStreamTxt.Position = FileStreamTxt.Size) then begin
Memo1.Lines.Add(StringReplace(Linha, LineEnding, '', [rfReplaceAll, rfIgnoreCase]));
Linha := '';
end;
end;
finally
FreeAndNil(FileStreamTxt);
end;
end;
procedure TForm1.ButtonSalvarClick(Sender: TObject);
var
Linha: String;
Indice: Integer;
FileStreamTxt: TFileStream;
begin
if Memo1.Lines.Count > 0 then
if SaveDialog1.Execute then
try
FileStreamTxt := TFileStream.Create(SaveDialog1.FileName, fmCreate or fmShareDenyWrite);
for Indice := 0 to Memo1.Lines.Count - 1 do begin
Linha := Memo1.Lines.Strings[Indice] + LineEnding;
FileStreamTxt.WriteBuffer(Linha[1], Length(Linha));
end;
finally
FreeAndNil(FileStreamTxt);
end;
end;
end.
view raw unit1.pas hosted with ❤ by GitHub

Bem, o projeto acima pode não demonstrar a eficiência do TFileStream, mas mostra a simplicidade de usá-lo. Basicamente a única coisa que precisamos nos preocupar é com o LineEnding que marca o fim de cada linha de um arquivo texto. Talvez um bom exemplo seja a gravação de dados em um arquivo de log de grande tamanho. Neste caso, o código para salvar as linhas ficaria bem parecido com o método ButtonSalvarClick, do exemplo acima. A única coisa que mudaria seria a linha abaixo:

FileStreamTxt := TFileStream.Create(SaveDialog1.FileName, fmCreate or fmShareDenyWrite);

A qual seria melhor substituída pelo seguinte trecho:

if FileExistsUTF8(SaveDialog1.FileName) then begin
  FileStreamTxt := TFileStream.Create(SaveDialog1.FileName, fmOpenWrite or fmShareDenyWrite);

  FileStreamTxt.Position := FileStreamTxt.Size;
end else begin
  FileStreamTxt := TFileStream.Create(SaveDialog1.FileName, fmCreate or fmShareDenyWrite);
end;

O trecho acima garante que o arquivo não tenha seu conteúdo anterior apagado caso o arquivo já exista no caminho indicado. Assim as linhas serão adicionadas ao arquivo, algo mais lógico para quem está gravando informações em um log que tem dias e mais dias de conteúdo previamente gravado.

Outra ressalva a fazer, no método ButtonAbrirClick, é que o comando TMemo.Lines.Add adiciona automaticamente o LineEnding, sendo necessário, neste caso, remover este da linha a ser inserida, usando o comando StringReplace. Se for tratar o arquivo diretamente no TFileStream talvez não seja necessário usar este recurso.

Esta dica deve funcionar no Windows, Linux e Mac. Mais informações em: http://wiki.freepascal.org/File_Handling_In_Pascal

[]'s,

Ericson Benjamim.

Nenhum comentário:

Postar um comentário