 |
ActiveDelphi .: O site do programador Delphi! :.
|
Exibir mensagem anterior :: Exibir próxima mensagem |
Autor |
Mensagem |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Ter Jan 28, 2014 12:31 am Assunto: [Dúvida] Tfilestream extremamente lento o que pode ser? |
|
|
[Dúvida] Tfilestream extremamente lento o que pode ser?
Estou fazendo um editor hexadecimal...
e ele fica muiiiiito lento, demora alguns minutos para ler um arquivo de 4MB.
o mesmo arquivo quando lido em editores profissionais pegos na internet
abre instantaneamente.
para verificar se não era erro de demora por causa de componentes utilizados dei uma limpada geral no code e fiz bem simples (apenas le o arquivo e coloca byte a byte em um memo:
Código: |
while arqpeq.Position < arqpeq.Size do
begin
//BAR1.Position:= ARQpeq.Position;
ARQpeq.Read(alin,1);
memo1.Lines.Add(strtoint(alin));
end;
|
se fica lento com 4MB imagina se eu abrir um arquivo de 100 megas...
ja tentei colocar com laços FOR, e REPEAT tambem... mas deu praticamente na mesma...
tentei ler mais de um byte por vez... ex: ARQpeq.Read(alin,32);
deu uma boa melhorada...
mas neste caso tenho que fazer uma função para dividir a string gerada por 32... dai aumenta mais ainda o code...
tentei usar TMemorystream...
mas tive problema com arquivos grandes...
outra coisa se eu habilitar a barra de status (comentada no code)
dai que fica uma carroça de vez... existe alguma forma de melhorar esta colocação da barra de progresso?
alguém poderia me dar uma luz, apresentando alguma forma mais rápida de ler arquivos?
obrigado a todos. |
|
Voltar ao Topo |
|
 |
joemil Moderador

Registrado: Quinta-Feira, 25 de Março de 2004 Mensagens: 9100 Localização: Sinop-MT
|
Enviada: Ter Jan 28, 2014 7:42 am Assunto: |
|
|
se vc pegou mais de um caracter e melhorou, acho q se vc fizer um FOR dentro do laco WHILE nao deve aumentar mto o processamento, assim:
while arqPeq.Position < arqPeq.Size do
begin
arqPeq.Read(alin, 32);
for x := 1 to 32 do
Memo1.Lines.Add(strtoint(alin[x]));
end; _________________ <b>SEMPRE COLOQUE [RESOLVIDO] NO SEU POST</b>
Enviar imagens: http://tinypic.com/ |
|
Voltar ao Topo |
|
 |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Ter Jan 28, 2014 3:15 pm Assunto: resp |
|
|
ele melhorou com esta forma de colocar para ler 32 bytes por vez...
mas ainda não chega perto dos editores concorrentes.
pois com este esquema (32 por vez) ele demora alguns segundos para ler o arquivo (+- 4megas) sem os 32 bytes por vez ele demorava minutos...
mas nos softs prontos da web o mesmo arquivo abre instantaneamente...
cheguei a pensar que os softs que eu citei abrissem rápido por que não abriam o arquivo por completo... (abririam por partes conforme vai descendo a barra de rolagem do programa ele iria lendo novos dados...)
mas acabei por pensar que não era assim, pois quando pesquiso por alguma coisa mesmo por algum dado que sei que está no fim do do arquivo, ele acha instantaneamente... ou seja acho que arquivo já está carregado por completo.
devo estar fazendo algo de errado, ou minha lógica de programação está muito errada... ou será que pode ser que o delphi demore para fazer este tipo de leitura? desde já agradeço a todos... |
|
Voltar ao Topo |
|
 |
marcieldeg Colaborador


Registrado: Terça-Feira, 5 de Abril de 2011 Mensagens: 1054 Localização: Vitória - ES
|
Enviada: Ter Jan 28, 2014 4:26 pm Assunto: |
|
|
Acredito que os softwares comerciais não leiam todo o arquivo de uma vez, e sim somente o que "cabe na tela". O resto do arquivo é lido por demanda, de acordo com que o usuário vai rolando o texto. |
|
Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Ter Jan 28, 2014 4:52 pm Assunto: |
|
|
seu problema estar nesta linha
memo1.Lines.Add(strtoint(alin));
você estar adicionando texto no memo linha a linha isso vai deixar sua aplicação muito lenta ao abrir o arquivo.
em vez de adicionar linha a linha use a propriedade lines.text do memo mas antes trate os dados a ser lido previamente com um tstrings e por final passe para o memo.
algo do tipo
Código: |
list:=tstringlist.create;
list.Add(strtoint(alin));
depois de realizado o processo da leitura do arquivo
memo1.Lines.Text:=list.Text;
list.free;
|
pronto vai ter o arquivo todo no memo de forma instantânea
espero ter ajudado  |
|
Voltar ao Topo |
|
 |
marcieldeg Colaborador


Registrado: Terça-Feira, 5 de Abril de 2011 Mensagens: 1054 Localização: Vitória - ES
|
Enviada: Ter Jan 28, 2014 10:01 pm Assunto: |
|
|
strak2012, você acertou na trave na solução...
Ao setar uma linha na propriedade Lines, o componente visual dá um repaint no componente, causando parte do delay. Para resolver isso, não é necessário criar um TStringList, pois a propriedade Lines do Memo já é um TStringList, o que causaria um consumo de memória desnecessário e um overhead para mover o texto de um objeto ao outro. Só precisamos desativar as atualizações do Memo a cada linha adicionada, e executá-la uma única vez no fim do processamento.
cetics, acredito que a alteração abaixo agilize bastante:
Código: | Memo1.Lines.BeginUpdate; // esse é o "ó do borogodó"
try
while arqpeq.Position < arqpeq.Size do
begin
//BAR1.Position:= ARQpeq.Position;
ARQpeq.Read(alin,1);
Memo1.Lines.Add(StrToInt(alin));
end;
finally
Memo1.Lines.EndUpdate; //
end; |
|
|
Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Qua Jan 29, 2014 5:43 am Assunto: |
|
|
Antes de mais nada quero parabenizar marcieldeg por sua solução e colocação e não querendo desmerecer sua solução, a qual foi muito interessante, inteligente e pratica e diria até a mais correta, contudo isso deixou-me uma duvida.
Visto isso resolvi realizar teste de desempenho ao usar os dois métodos.
Código: | //teste 1
procedure TForm2.Button1Click(Sender: TObject);
var
x: longint;
tmp: tdatetime;
begin
tmp := now;
Memo1.Clear;
Memo1.Lines.BeginUpdate; // esse é o "ó do borogodó"
try
for x := 1 to 500000 do // 488 KB
Memo1.Lines.Add(inttostr(x));
finally
Memo1.Lines.EndUpdate; //
end;
Label1.Caption := formatdatetime('HH:NN:SS', now - tmp);
end;
//teste2
procedure TForm2.Button2Click(Sender: TObject);
var
x: longint;
tmp: tdatetime;
list:tstrings;
begin
tmp := now;
Memo1.Clear;
list := tstringlist.Create;
for x := 1 to 500000 do // 488 KB
list.Add(inttostr(x));
Memo1.Lines.Text := list.Text;
list.Free;
Label2.Caption := formatdatetime('HH:NN:SS', now - tmp);
end;
|
E para minha surpresa a solução que nosso colega marcieldeg propôs mostra mais lenta ao realizar a tarefa do código acima levando 1 minuto e 2 segundos, enquanto a minha só levou 7 segundos.
Isso para um numero 500.000 byte que supostamente seria lido, estamos falando de 488 kb apenas, o que dizer 10mb.
Desde já não estou a falar que a solução proposta pelo marcieldeg não seja a correta só a mais lenta.
meus testes
 |
|
Voltar ao Topo |
|
 |
johnny-walker Moderador


Registrado: Sábado, 4 de Outubro de 2003 Mensagens: 10653 Localização: Contagem/MG - BRAZIL
|
Enviada: Qua Jan 29, 2014 10:40 am Assunto: |
|
|
Concordo com o pessoal em relação ao beginupdate e endupdate, com isto melhora bastante a performance. Mas é possível melhorar também a leitura do stream utilizando um buffer mair, mas que não deve ser maior que a capacidade de leitura da stringlist. De um olhada na vcl e veja o código de leitura do stringlist, verificando o tamanho do buffer.
Bye _________________ P.O.W.E.R B.Y D.E.L.P.H.I |
|
Voltar ao Topo |
|
 |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Qua Jan 29, 2014 1:21 pm Assunto: obrigado |
|
|
pessoal, muito obrigado por todas as respostas...
eu tinha tentado (antes de ler estas respostas)
fazer o seguinte:
a cada byte que o programa ia lendo, ele ia adicionando num arquivo de texto (em disco) depois de pronto dava um loadfromfile para o memo e carregava o arquivo...
isso deixou o processo bem rápido, mas como pretendo usar em arquivos na casa dos gigas, caso fosse ler um arquivo de um giga teria que ter outro giga livre no disco para fazer esta operação...
vou testar as soluções apresentadas aqui... acho que agora vai dar certo...
só fiquei com algumas dúvidas dúvida:
quanto cabe em um memo? ou num stringgrid? (este ultimo que estou pensando em usar...)
tipo se eu ler um arquivo de alguns gigas estes dados caberãom em um memo ou stringgrid?
obrigado a todos. |
|
Voltar ao Topo |
|
 |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Qua Jan 29, 2014 2:14 pm Assunto: |
|
|
Acho que estou fazendo algo errado...
os procedimentos apresentados aceleraram bastante, mas ainda ficou algo no ar, o que está acontecendo é o seguinte:
quando executo o programa ele demora vários segundos e depois apresenta o texto todo de uma vez (instantaneamente) mas o problema são estes vários segundos (diminuíram bastante depois de aplicar as soluções acima) mas ainda demora um pouco, vou postar aqui o code que estou usando com as duas soluções. e mais algumas funções tiradas da net para lidar com as conversões:
//=================
Código: | unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Edit1: TEdit;
Button1: TButton;
OpenDialog1: TOpenDialog;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure HexDump(var data; size: Integer; s: TStrings);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function HexB (b: Byte): String;
const HexChar: Array[0..15] of Char = '0123456789ABCDEF';
begin
result:= HexChar[b shr 4]+HexChar[b and $0f];
end;
procedure tform1.HexDump(var data; size: Integer; s: TStrings);
const
sepHex=' ';
sepAsc=' ';
nonAsc='.';
var
i : Integer;
hexDat, ascDat : String;
buff : Array[0..1] of Byte Absolute data;
begin
hexDat:='';
ascDat:='';
for i:=0 to size-1 do
begin
hexDat:=hexDat+HexB(buff[i]);
if ((buff[i]>31) and (buff[i]<>255)) then
ascDat:=ascDat+Char(buff[i])
else
ascDat:=ascDat+nonAsc;
if (((i+1) mod 16)<>0) and (((i+1) mod 8)=0) then
hexDat:=hexDat+sepHex;
if ((i+1) mod 16)=0 then
begin
s.Add(hexdat+sepAsc+ascdat);
hexdat:='';
ascdat:='';
end;
end;
if (size mod 16)<>0 then
begin
if (size mod 16)<8 then
hexDat:=hexDat+StringOfChar(' ',(8-(size mod 8))*2)
+sepHex+StringOfChar(' ',16)
else
hexDat:=hexDat+StringOfChar(' ',(16-(size mod 16))*2);
s.Add(hexDat + sepAsc + ascDat);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
opendialog1.Execute;
edit1.Text:= opendialog1.FileName;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FStream: TFileStream;
buff: array[0..$fff] of Byte;
nRead: Integer;
begin
FStream := TFileStream.Create(edit1.text, fmOpenRead or fmShareDenyWrite);
Memo1.Lines.BeginUpdate;
try
repeat
nRead := FStream.Read(Buff, SizeOf(Buff));
if nRead<>0 then
hexdump(buff,nRead,memo1.lines);
until nRead=0;
finally
FStream.Free;
Memo1.Lines.EndUpdate;
end;
end;
end. |
//=================
Cheguei até a pensar o seguinte, o Editor hexa que uso como exemplo de performance é o editor que vem embutido no virtualdub, e por se tratar de um programa de código aberto estou pensando em baixar o code e dar uma olhada no que eles usaram. só tem um problema no about do VD diz que foi compilado com visual studio e não entendo muito das linguagens utilizadas por ele... vou ver se consigo, obrigado a todos. |
|
Voltar ao Topo |
|
 |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Qua Jan 29, 2014 2:22 pm Assunto: |
|
|
outra forma que usei:
Código: | unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Edit1: TEdit;
Button1: TButton;
OpenDialog1: TOpenDialog;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure HexDump(var data; size: Integer; s: TStrings);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
list: tstringlist;
implementation
{$R *.dfm}
function HexB (b: Byte): String;
const HexChar: Array[0..15] of Char = '0123456789ABCDEF';
begin
result:= HexChar[b shr 4]+HexChar[b and $0f];
end;
procedure tform1.HexDump(var data; size: Integer; s: TStrings);
const
sepHex=' ';
sepAsc=' ';
nonAsc='.';
var
i : Integer;
hexDat, ascDat : String;
buff : Array[0..1] of Byte Absolute data;
begin
hexDat:='';
ascDat:='';
for i:=0 to size-1 do
begin
hexDat:=hexDat+HexB(buff[i]);
if ((buff[i]>31) and (buff[i]<>255)) then
ascDat:=ascDat+Char(buff[i])
else
ascDat:=ascDat+nonAsc;
if (((i+1) mod 16)<>0) and (((i+1) mod 8)=0) then
hexDat:=hexDat+sepHex;
if ((i+1) mod 16)=0 then
begin
s.Add(hexdat+sepAsc+ascdat);
hexdat:='';
ascdat:='';
end;
end;
if (size mod 16)<>0 then
begin
if (size mod 16)<8 then
hexDat:=hexDat+StringOfChar(' ',(8-(size mod 8))*2)
+sepHex+StringOfChar(' ',16)
else
hexDat:=hexDat+StringOfChar(' ',(16-(size mod 16))*2);
s.Add(hexDat + sepAsc + ascDat);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
opendialog1.Execute;
edit1.Text:= opendialog1.FileName;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FStream: TFileStream;
buff: array[0..$fff] of Byte;
nRead: Integer;
begin
list:=tstringlist.create;
FStream := TFileStream.Create(edit1.text, fmOpenRead or fmShareDenyWrite);
try
repeat
nRead := FStream.Read(Buff, SizeOf(Buff));
if nRead<>0 then
hexdump(buff,nRead,list);
until nRead=0;
finally
FStream.Free;
memo1.Lines.Text:=list.Text;
list.free;
end;
end;
end. |
|
|
Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Qua Jan 29, 2014 4:14 pm Assunto: |
|
|
Em memo é perto 2 gigas de caractres, se usares 3 caracteres para representar um byte estará limitado a ler arquivos por volta dos 665 mb.
Stringgrid deve ser bem menor.
Se há necessidade de leitura e escrita de arquivos muitos grande não carregue-o todo no memo, será desnecessário ocupar tanta memoria com dados que não serão alterados e muito pouco provável visto, em vez disso estude as rotinas, read, write, seek, BlockRead, BlockWrite.
Assim você só exibe no memo parte do arquivo que vai trabalhar, é como trabalhar com paginas, a pagina atual é o bloco lido do arquivo e este é o que deve ser exibido no memo, você pode voltar a pagina anterior lendo o bloco anterior, como pode ir para pagina seguinte lendo o próximo bloco.
links para dares uma olhada.
http://www.delphibasics.co.uk/RTL.asp?Name=Seek
http://www.delphibasics.co.uk/RTL.asp?Name=BlockRead
http://www.delphibasics.co.uk/RTL.asp?Name=BlockWrite |
|
Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Qua Jan 29, 2014 4:24 pm Assunto: |
|
|
Isso me fez lembrar de um editor hex que fiz a muitos anos em turbo pascal 7.0, claro que não tínhamos Tmemo, Tstrings nada disso kkkkk, mas as rotinas que mencionei vem desde o turbo pascal. |
|
Voltar ao Topo |
|
 |
cetics Novato

Registrado: Terça-Feira, 8 de Novembro de 2011 Mensagens: 40
|
Enviada: Qui Jan 30, 2014 1:37 pm Assunto: obrigado |
|
|
Obrigado pessoal,
gostei muito do forum, o pessoal é muito bacana.
vou dar uma olhada nos materiais citados.
Não sei como editar para colocar [Resolvido].
Obrigado a todos. |
|
Voltar ao Topo |
|
 |
|
|
Enviar Mensagens Novas: Proibido. Responder Tópicos Proibido Editar Mensagens: Proibido. Excluir Mensagens: Proibido. Votar em Enquetes: Proibido.
|
|