sábado, julho 15, 2006

Pesquisa de arquivos




Buscar arquivos num diretório ou subdiretório exige conhecimento de uma coisa simples mas que pode causar problemas: fazer uma função chamar ela mesma. Às vezes a função não mantém registro do status de sua execução e então uma próxima execução não é controlada de maneira correta e pode haver o tal Stack Overflow (a recursividade "infinita").

Para pesquisar arquivos em diretórios usa-se as funções FindFirst, FindNext e FindClose.

FindFirst - deve ser usada pelo menos uma vez. É a função que inicia o processo de pesquisa, recebendo os parâmetros iniciais e retornando o resultado da pesquisa de acordo com esses parâmetros (que são atribuídos ao registro do tipo TSearchRec, passado como parâmetro a essa função). Se retornar zero, pelo menos um arquivo foi encontrado.

function FindFirst(const Path: string; Attr: Integer;
var F: TSearchRec): Integer;

As máscaras (*) são usadas na variável Path que passada para a função FindFirst. Por exemplo, para que a função retorne somente os arquivos do word da pasta C:\Meus Documentos, os parâmetros seriam:

FindFirst('C:\MEUS DOCUMENTOS\*.DOC', faAnyFile, sr)

faAnyfile indica qualquer arquivo. Esse segundo parâmetro informa a função que qualquer arquivo pode ser retornado sendo os arquivos divididos nessas categorias:

Constante Descrição

faReadOnly arquivos marcados como "somente leitura"
faHidden arquivos ocultos
faSysFile arquivos do sistema
faVolumeID arquivos" que representam drives - C, D, A..
faDirectory diretórios (sim, são arquivos)
faArchive arquivos de arquivamento - será isso?
faAnyFile qualquer um dos citados


O resultado de FindFirst é armazenado no terceiro parâmetro, nesse caso é a variável sr. Na próxima função eu explico o que existe nesse parâmetro.


FindNext - É usada até que retorne um código de erro, que indica que a função não encontrou mais arquivos. As informações sobre cada arquivo são passadas a essa função pelo parâmetro do tipo TSearchRec usado na função FindFirst.

TSearchRec = record
Time: Integer;
Size: Integer;
Attr: Integer;
Name: TFileName;
ExcludeAttr: Integer;
FindHandle: THandle;
FindData: TWin32FindData;
end;


Abaixo, o código fonte:




unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileCtrl, ExtCtrls;

type
TForm1 = class(TForm)
ListBox1: TListBox;
Panel1: TPanel;
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
DirectoryListBox1: TDirectoryListBox;
CheckBox1: TCheckBox;
DriveComboBox1: TDriveComboBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
StartTime: Cardinal;
Recursive: Integer;
procedure FindFiles(const sDirectory: string;
const SearchSubfolders: boolean = true);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FindFiles(const sDirectory: string;
const SearchSubfolders: boolean = true);
var
sr: TSearchRec;
begin
if DirectoryExists(sDirectory) then
try
if Recursive <= 0 then
begin
StartTime:= GetTickCount;
Recursive:= 0;
ListBox1.Clear;
ListBox1.Items.Add('Procurando por '+edit1.Text);
end;

if SysUtils.FindFirst(sDirectory+'\*.*',
faAnyFile, sr) = 0 then
begin
repeat
case sr.Attr of
faDirectory:
if SearchSubfolders then
if (Sr.Name <> '.') and
(Sr.Name <> '..') then
begin
Inc(Recursive);
FindFiles(sDirectory +'\'+ sr.Name);
end;
else
if Pos(AnsiUpperCase(Edit1.Text),
AnsiUpperCase(sr.Name)) <> 0 then
ListBox1.Items.Add(sDirectory + '\' + sr.Name);
end;

until SysUtils.FindNext(sr) <> 0;
end;

finally
SysUtils.FindClose(sr);
Dec(Recursive);
if Recursive < 0 then
begin
ListBox1.Items.Add('Terminado em '
+IntToStr(GetTickCount - StartTime)+'ms.');
ListBox1.ItemIndex:= ListBox1.Count-1;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
FindFiles( DirectoryListBox1.Directory, CheckBox1.Checked);
end;

end.

Código fonte transformado em HTML por http://tohtml.com/pascal/


Gostou? Sugere alguma coisa? Comente!

Tchau, suporte!

Tchau suporte técnico, tchau consultoria, tchau isso tudo. É hora de me concentrar em matemática, física e modelagem de elementos gráficos e texturas de fundo e coisa sdo tipo.

RPG baseado em tijolinhos

Quem consegue controlar elementos gráficos que não são gerados por código? Quais são os limites da representação do mundo quando a matemática ou a arquitetura do sistema interferem profundamente no modo de tornar isso possível? Se fosse possível pincelar código seria uma maravilha.. acho que é melhor pincelar nossa mente antes de programar..

Para programar uma cena de um jogo de RPG por exemplo. Estou com uma interrogação tremenda. Há diversos artigos na internet mas eu nunca os compreendo completamente. Paciência ...

Sinuoso


A sinuosidade provocante das formas.. seios.. cabelos.. a fonte de inspiração pro programador..
umbigo, bunda, perna, boca, olhos..

sexta-feira, julho 14, 2006

Estatística e Compressão JPEG

Esse link deve interessar quem quiser saber como as imagens JPEG são compactadas e descompactadas. Clique no botão abaixo.



Convertendo Bitmap para JPEG

Quer transformar o seu arquivo de bitmap grande num arquivo jpeg comprimido? Use a classe TJpegImage para isso. Fácil, acessível, funcional.. mas nada além disso.

procedure TForm1.Button1Click(Sender: TObject);
var
b: Tbitmap;
j: TJPEGImage;
Od: TOpenDialog;
begin
try
Od:= TOpenDialog.Create(Self);
od.Filter:= 'Bitmaps (*.bmp)|*.bmp';
if od.Execute then
try
b:= tbitmap.create;
j:= TJPEGImage.Create;
b.LoadFromFile(od.FileName);
j.Assign(b);
j.SaveToFile(ChangeFileExt(od.FileName, '.jpeg'));
finally
b.free;
j.free;
end;
finally
od.Free;
end;
end;

código fonte transformado em html em: http://tohtml.com/pascal/

Medir intervalos sem Timer...

GetTickCount (WinAPI)

A função GetTickCount retorna o número de milisegundos que passaram desde quando o windows foi iniciado (o pc foi ligado) pela ultima vez.

Se você tem uma função que consome 90% da CPU e que é executada sempre que um evento ocorre (quando uma barra de rolagem muda, por exemplo) e o usuário resolveu brincar de mandar mensagens então é hora de refazer seu programa e criar camadas que protejam o usuário de brincar tanto com código que pode fazer o PC travar. Não quer usar timers? Use GetTickCount. Como? Meça o intervalo de tempo entre o a ultima execução da função (armazene isso numa variável) e o início da execução atual. Se o intervalo for menor que um limite mínimo a função sai e se não, continua.


Acesso a Arquivos com várias estruturas

Windows FileMapping (WinAPI)










Já tentou acessar um arquivo através de pedaços com BlockRead, BlockWrite? Funciona bem com registros para arquivos estruturados. E para arquivos que podem assumir diversas estruturas (por exemplo, você quer ler um byte na posição 3000 e um registro na posição 2999, um objeto na posição 300, um inteiro na posição 900, um byte negativo na posição 10000... e tudo sem precisar declarar variáveis para intermediar essa leitura nem dar conta do buffer desse arquivo)?


Criar arquivos complexos não é dificil. É só querer armazenar mais de uma coisa num lugar só e é muito comum quando se tem um formato de arquivo que junte elementos diferentes. Para arquivos que têm só texto, um cabeçalho (header) que descreva o tamanho da letra (fonte), a cor ou outros detalhes um acesso estruturado serviria. E para arquivos que juntam texto, som, imagens e estruturas diversas, criadas por você?

Generalizar o acesso ao arquivo tratando-o como uma sequencia de bytes (usando o tipo file of byte) não dá acesso indexado maleável porque não evita o uso de buffers para transferir do o que você quer do arquivo para a memória.

E se você quisesse o arquivo na memória de maneira imediata sem se preocupar com o acesso e com leituras para variáveis?

Use o FileMapping. O Windows cuida de tudo. E você ganha um ponteiro que pode ser usado com o tipo que você quiser, fazendo o arquivo representar aquilo que você quiser sem precisar usar variáveis intermediárias. Depois, faça typecast dos tipos. Para arquivos feitos por você vale a pena descrever tipos que facilitem o acesso a esses arquivos criando registros que representem esse arquivo dependendo do tipo de informação que se quer acessar.

Canvas e Skins do Winamp


GetWindowDC (WinAPI)

Às vezes o winamp trava e acusa que desenha seus skins sobre sua janela depois do windows. É quando eu posso ver que o winamp é "humano" porque ele usa os handles normais de janela que qualquer outro programa só que ele ultrapassa e desenha sobre o canvas da janela inteira (incluindo a barra de título - caption bar). Como se faz isso? WinAPI.
A função GetWindowDC retorna o que é explicado aqui:

The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.

Quer dizer que se você passar o handle de uma janela pra essa função ela retorna um índice controlador de contexto de dispositivo gráfico que te permite desenhar na janela inteira, sobrescrevendo o que normalmante você vê (botões minimizar, maximizar, etc). Isso permite capturar o desktop, capturar conteúdo de outros programas, capturar tudo que possa se transformar em Device Context pelo Windows. Que maravilha, hein?

Sem VCL ?


Terrenos aquosos, terrenos moles, ligados por cores fortes e sinais vermelhos, limites de memória e de inspiração, a estética fixada e dura do código assembly final e a GDI do Windows encobrindo o que se passa internamente.

Já pensei em me livrar da facilidade dos componentes da VCL para ver se aguentava criar um programa Windows a partir do zero e foi impossível. Queria usar pouco código e saber o que o programa estava fazendo mas isso é improdutivo porque em abiente RAD isso fica por conta da ferramenta a maior parte do tempo. Tentei enxergar a programação como um oásis nas montanhas: a água está nos pontos mais baixos.
O código da VCL é uma maravilha. É hora de usar RAD mesmo e parar de vangloriar o C, o Assembly.. por enquanto isso está fora do meu alcance.

Pesquisa no Blog:
Web DelphiEArte.blogspot.com