ActiveDelphi - Índice do Fórum ActiveDelphi
.: O site do programador Delphi! :.
 
 FAQFAQ   PesquisarPesquisar   MembrosMembros   GruposGrupos   RegistrarRegistrar 
 PerfilPerfil   Entrar e ver Mensagens ParticularesEntrar e ver Mensagens Particulares   EntrarEntrar 

[Dúvida] Tfilestream extremamente lento o que pode ser?

 
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Delphi
Exibir mensagem anterior :: Exibir próxima mensagem  
Autor Mensagem
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Ter Jan 28, 2014 12:31 am    Assunto: [Dúvida] Tfilestream extremamente lento o que pode ser? Responder com Citação

[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
Ver o perfil de Usuários Enviar Mensagem Particular
joemil
Moderador
Moderador


Registrado: Quinta-Feira, 25 de Março de 2004
Mensagens: 9100
Localização: Sinop-MT

MensagemEnviada: Ter Jan 28, 2014 7:42 am    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Ter Jan 28, 2014 3:15 pm    Assunto: resp Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
marcieldeg
Colaborador
Colaborador


Registrado: Terça-Feira, 5 de Abril de 2011
Mensagens: 1054
Localização: Vitória - ES

MensagemEnviada: Ter Jan 28, 2014 4:26 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Ter Jan 28, 2014 4:52 pm    Assunto: Responder com Citação

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 Smile
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
marcieldeg
Colaborador
Colaborador


Registrado: Terça-Feira, 5 de Abril de 2011
Mensagens: 1054
Localização: Vitória - ES

MensagemEnviada: Ter Jan 28, 2014 10:01 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Qua Jan 29, 2014 5:43 am    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
johnny-walker
Moderador
Moderador


Registrado: Sábado, 4 de Outubro de 2003
Mensagens: 10653
Localização: Contagem/MG - BRAZIL

MensagemEnviada: Qua Jan 29, 2014 10:40 am    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular MSN Messenger
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Qua Jan 29, 2014 1:21 pm    Assunto: obrigado Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Qua Jan 29, 2014 2:14 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Qua Jan 29, 2014 2:22 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Qua Jan 29, 2014 4:14 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Qua Jan 29, 2014 4:24 pm    Assunto: Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
cetics
Novato
Novato


Registrado: Terça-Feira, 8 de Novembro de 2011
Mensagens: 40

MensagemEnviada: Qui Jan 30, 2014 1:37 pm    Assunto: obrigado Responder com Citação

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
Ver o perfil de Usuários Enviar Mensagem Particular
Mostrar os tópicos anteriores:   
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Delphi Todos os horários são GMT - 3 Horas
Página 1 de 1

 
Ir para:  
Enviar Mensagens Novas: Proibido.
Responder Tópicos Proibido
Editar Mensagens: Proibido.
Excluir Mensagens: Proibido.
Votar em Enquetes: Proibido.


Powered by phpBB © 2001, 2005 phpBB Group
Traduzido por: Suporte phpBB