Ir al contenido


Foto

Consulta con FindFirst


  • Por favor identifícate para responder
30 respuestas en este tema

#21 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 04 noviembre 2011 - 06:37

Disculpen la demora, aquí les traigo el versión de 32bits del programa para que lo prueben
también quiero comunicarles que he logrado que no se cuelgue la aplicación mediante el
código:


delphi
  1. application.ProcessMessages;



y este es el código completo:



delphi
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   //Classes, windows, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, SysUtils ;
  9.     Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, windows, UNIT2  ;
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Edit1: TEdit;
  17.     Label1: TLabel;
  18.     Memo1: TMemo;
  19.     StaticText1: TStaticText;
  20.     procedure Button1Click(Sender: TObject);
  21.   private
  22.     { private declarations }
  23.   public
  24.     { public declarations }
  25.   end;
  26.  
  27. var
  28.   Form1: TForm1;
  29.  
  30. implementation
  31.  
  32. {$R *.lfm}
  33.  
  34. { TForm1 }
  35.  
  36. procedure TForm1.Button1Click(Sender: TObject);
  37.   procedure ChangeAttributes(const path:String);
  38.       var
  39.         search : TSearchRec;
  40.         nFiles : integer;
  41.         cPath : String;
  42.       begin
  43.       application.ProcessMessages;    // ESTE HACE QUE NO SE CUELGUE EL PROGRAMITA... :)
  44.       cpath:=path {GetCurrentDir+'\';};
  45.       nfiles:=findfirst(cpath + '*.*', faanyfile, search);
  46.  
  47.       while nfiles = 0 do
  48.  
  49.       begin
  50.         if search.Attr = fadirectory then
  51.         begin
  52.         repeat
  53.         memo1.Lines.Add(search.Name);      // FUNCIONA
  54.  
  55.           if (search.Name<>'.') and (search.Name<>'..') then
  56.           begin
  57.               setfileattributes(Pchar(cpath+search.Name), FILE_ATTRIBUTE_NORMAL);
  58.               ChangeAttributes(path + search.Name + '\'); 
  59.  
  60.           end;
  61.           until (FindNext(search) <> 0);
  62.  
  63.         end
  64.         else
  65.         repeat
  66.         SetFileAttributes(PChar(cPath + search.Name),FILE_ATTRIBUTE_NORMAL);
  67.         ChangeAttributes(path + search.Name + '\');
  68.  
  69.         until FindNext(search) <> 0;
  70.  
  71.         nFiles:=FindNext(Search);
  72.         end;
  73.         SysUtils.FindClose(search);
  74.         end;
  75.  
  76. begin
  77.  
  78.     ChangeAttributes(GetCurrentDir+'\');
  79.  
  80. end;
  81. end.




como les comentaba, este código me está ayudando mucho de momento, aunque les cuento que
después de comprimirlo con el UPX me trabaja colgandose como si no le hubiera puesto
el "application.ProcessMessages", pienso que debe ser por el uso del UPX para comprimirlo
de todas maneras estaré al tanto.....

PD: Les mando la versión de 32 bit sin UPX ......espero sus comentarios amigos ...

  • 0

#22 cadetill

cadetill

    Advanced Member

  • Moderadores
  • PipPipPip
  • 994 mensajes
  • LocationEspaña

Escrito 06 noviembre 2011 - 02:33

Buenas,

Sigues teniendo bucles innecesarios, fíjate en mi código o el que te pasó en su día escafandra, verás que sólo hay 1.

Luego, sólo quiero aclararte lo del ProcessMessage. El hecho de que "no se cuelgue el programa" es debido a que ProcessMessages procesa la cola de mensajes de Windows. Como te comentó escafandra, eso es peligroso en procesos recursivos por posibles reentradas. Tenlo en cuenta. Si el proceso no dura mucho (que no creo), casi mejor que parezca que "se congele" la aplicación y evitar reentradas (entiendo que por el nivel que tienes meterte en temas de threads puede superar tus conocimientos).

Nos leemos
cadetill
  • 0

#23 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 06 noviembre 2011 - 07:42

Buenas y gracias por tu comentario amigo cadetill, voy a hacer lo posible para limpiar el código.... de tantos bucles...  y también tengo una duda referente a la "reentrada" que se refieren, pienso que debe ser si por error oprimo el mismo botón de proceso dos veces.... si es así estoy viendo deshabilitar el botón principal cuando se inicie el proceso como tu comentabas.... bueno espero hacerlo bien...... saludos a TODOS.  :)


PD: Es realmente malo tener un par de bucles de más aunque de momento funcionen
y que significa "cola de mensajes de Window" en processmessage.... :)
  • 0

#24 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 06 noviembre 2011 - 09:01

Hola monchito_elroro,


No te preocupes demasiado por el tema de los bucles, si recién estás empezando es lógico que te cueste apreciar si hay código redundante. A todos nos pasó (y/o nos sigue pasando) alguna vez.


Yo antes hacía redundancias como éstas:




delphi
  1. if Encontrado = true
  2.   then ....




Que puede mejorarse:




delphi
  1. if Encontrado
  2.   then ....




En el tema de los ciclos es algo más difícil. Pasa más por una organización de nuestras ideas, de desarrollar la lógica y algoritmia. Lamentablemente (o afortunadamente, según como mires) sólo hay un modo de aprender y mejorar: ¡seguir practicando! A medida en que avanzas tu cabeza gana puntos, se va acostumbrando y hasta te diría que algunas cosas se vuelven triviales, básicas y te salen espontáneamente. Así es que vas a encontrar, y desarrollar, en el ejercicio diario consejos, tips y "trucos" que te ayudan hacer de la programación algo más gratificante.


En lo particular, en lo que hace a ciclos yo diría que deben recordarse algunas reglas de oro:
1) Volver a los fundamentos de programación y repasar los conceptos y características de cada ciclo:
A. While: requiere de una condición de entrada, y de no cumplirse no se ejecuta. Por tanto por definición si inicialmente no se satisfacen las condiciones ¡no se entra al ciclo! Pregúntate si realmente el ciclo ha de ejecutarse, o es algo meramente opcional.
B. Repeat: por naturaleza se ejecutará al menos una vez y requiere una condición de salida. Si en verdad el ciclo ha de llevarse a cabo, lo mejor es optar por repeat o, si se saben las condiciones finales e iniciales por el for.


Por ejemplo, muchas veces nos encontramos, y nos sale más fácil, con esto:




delphi
  1. encontrado = false;
  2. while NOT encontado do
  3. begin
  4. ...
  5. end;




Observa que ha sido necesario forzar al código a entrar al ciclo haciendo que la condición se cumpla, y además en la condición se está introduciendo un negado (en lo posible debe evitarse una evaluación por los negados). Es mucho más limpio su contraparte:




delphi
  1. repeat
  2. ....
  3. until encontrado




Observa que no ha sido necesario valores iniciales, no hay código forzoso. Como el ciclo siempre ha de tener lugar, con el repeat me aseguro de ello.


C. For: es ciclo más simple, y elemental, que se ejecutará una cantidad conocida de veces gracias a que se conocen los valores finales e iniciales de la variable de iteración.


Recomiendo la lectura de libros sobre algoritmia.


2. En parte relacionado con (1), evita en lo posible añadir cláusulas de escape como Exit, Continue que provoquen la ruptura prematura y la ejecución normal del ciclo. Si se puede saber y evaluar cuando ha de finalizar un ciclo, es mejor que esté como una condición y no como una salida forzada. Ejemplos típicos que veo:




delphi
  1. for i := 0 to Count - 1 do
  2. begin
  3.   // algo de código
  4.   if (condicion)
  5.     then begin
  6.               // algo para la condición
  7.               exit;
  8.             end;
  9. end;




Si lo analizamos friamente, si realmente es necesario dar por finalizado el ciclo ante el cumplimiento de una condición, ¡que ésta nos de la salida! Y no parte de la lógica del problema. Cambie el ciclo por un while o repeat según lo más adecuado:




delphi
  1. repeat
  2.   // algo de código
  3.   inc(i)
  4. until condicion OR (i = Count)




Y si es necesario obviar alguna iteración, por naturaleza del problema, es aceptable el uso de Continue. Dentro de todo es algo tolerable, pero si se puede evitar su uso, mejor.
La lección es: antes de finalizar un ciclo fuera de su naturaleza ¡piénselo dos veces!


3. Resulta algo curioso, en términos semánticos es mucho más fácil pensar en un repeat: "repetir algo hasta que..."; pero por alguna razón que no logro entender del todo, nos resulta más fácil pensar al momento de codificar en un while, cuya semántica es más liosa: "mientras ... hacer algo"
Con un repeat vemos efectivamente la condición de salida mientras que con el while la invertimos y la hacemos más oscura.
Piensa en salidas y luego en entradas. Recuerda: ¡Los ciclos deben terminar!


Si sólo pensamos en entradas, nos centramos más en un while. Tan es ese apego al while que en muchas veces el repeat es dejado de lado, y ni que decir... ¡hasta no reconocido!
Es decir: tendemos a hacer el doble de trabajo: reconocemos las salidas, pero la transformamos en una condición de entrada y ahora el código se adapta a esta nueva lógica.


No se porqué... pero es curioso, si das a elegir a muchos desarrolladores entre un while y un repeat que no te sorprenda si más de la mitad se inclina por el while. Yo tengo una teoría: como este requiere de una condición como entrada lo ven y sienten como un medio seguro en vez de delegarla para el final.


La lección: aprende a reconocer y practicar los tres ciclos. No te quedes únicamente con for y while. Hay mucho código escrito en while que con repeat sería mucho más claro. De hecho la realidad es que si tienes un ciclo y resulta ser que tus ideas todavía no te cuadran y cierran, ¡prueba con su contraparte!

Esto es apoyado por algo que comenté en paréntesis antes: evitar una lógica basado en negados. Si tienes muchos NOT, es un síntoma de que lo estás pensando al revés.


Con estos principios elementales, seguro que ahora tendrás las cosas más fresca, y estás más abierto a nuevas formas de hacer código.


4. Todo ciclo while y repeat es invertible. Es decir que un while se puede hacer en un repeat y a la inversa, un repeat en un while. Practica, por diversión, de vez en cuando pasando de uno a otro. Esto ayuda a que la cabeza recalibre y se entrene más.


5. Ten respeto a los ciclos, después del IF es la segunda estructura de control que más se utiliza. De hecho, cerca del 35% del código está compuesto por algún ciclo, sea for, while o repeat. Es mejor darle tiempo a revisarlo antes que confiarnos. Y si le sumamos las cláusulas de escape... ¡ni que decir, que hace más difícil hacer trazas al código!


Saludos,
  • 0

#25 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 06 noviembre 2011 - 11:22

Muchas gracias Delphius por el consejo, me viene muy importante y también comprensivo....
voy a darme el tiempo para practicarlo.... tienes razón en lo que dices.

tambien si no fuera mucha molestia quisiera exponer una parte del código que aún no me cuadra:
como dice:


delphi
  1. while nfiles = 0 do



según lo que entiendo (y he leído)    nfiles equivaldría a 0 si en caso se encuentra un archivo "tal"
y como lo veo supongo que mas o menos se estaría diciendo:

"Cuando" nfiles es igual a 0 "hacer"
....

pero lo que no me cuadra es como finaliza el while si siempre encontraría archivos....
Disculpen mi ignorancia...... :(

  • 0

#26 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 noviembre 2011 - 05:19

tambien si no fuera mucha molestia quisiera exponer una parte del código que aún no me cuadra:
como dice:


delphi
  1. while nfiles = 0 do



según lo que entiendo (y he leído)    nfiles equivaldría a 0 si en caso se encuentra un archivo "tal"
y como lo veo supongo que mas o menos se estaría diciendo:

"Cuando" nfiles es igual a 0 "hacer"
....

pero lo que no me cuadra es como finaliza el while si siempre encontraría archivos....


Mas delante tienes:


delphi
  1. nFiles:=FindNext(Search);


Eso hace que esa variable cambie de valor.
Deberías optimizar ese código...  :)


Saludos.

  • 0

#27 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 07 noviembre 2011 - 11:08

Muchas gracias Delphius por el consejo, me viene muy importante y también comprensivo....
voy a darme el tiempo para practicarlo.... tienes razón en lo que dices.

tambien si no fuera mucha molestia quisiera exponer una parte del código que aún no me cuadra:
como dice:


delphi
  1. while nfiles = 0 do



según lo que entiendo (y he leído)    nfiles equivaldría a 0 si en caso se encuentra un archivo "tal"
y como lo veo supongo que mas o menos se estaría diciendo:

"Cuando" nfiles es igual a 0 "hacer"
....

pero lo que no me cuadra es como finaliza el while si siempre encontraría archivos....
Disculpen mi ignorancia......

Más que "Cuando", está diciendo "mientras nfiles sea igual a 0 hacer"  ;)
Si fuera "Cuando" estaría dando a entender que es una acción temporal, y motivada justamente por dicho actor: el tiempo. Y además, esto sugeriría que no se tendría control alguno de los momentos en que se disparase algún evento o proceso que hiciera alterar el valor de nfiles.


Saludos,
  • 0

#28 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 07 noviembre 2011 - 12:54

Bueno amiguitos me he tomado un poquito de tiempo para tratar de modificar el código, de momento le he sacado el bucle "while" y este es el resultado:



delphi
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.       Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, windows, UNIT2  ;
  9. type
  10.  
  11.   { TForm1 }
  12.  
  13.   TForm1 = class(TForm)
  14.     Button1: TButton;
  15.     Edit1: TEdit;
  16.     Label1: TLabel;
  17.     Memo1: TMemo;
  18.     StaticText1: TStaticText;
  19.     procedure Button1Click(Sender: TObject);
  20.   private
  21.     { private declarations }
  22.   public
  23.     { public declarations }
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TForm1 }
  34.  
  35. procedure TForm1.Button1Click(Sender: TObject);
  36.   procedure ChangeAttributes(const path:String);
  37.       var
  38.         search : TSearchRec;
  39.         nFiles : integer;
  40.         cPath : String;
  41.       begin
  42.       application.ProcessMessages;    // ESTE HACE QUE NO SE CUELGUE EL PROGRAMITA... JEEEEE
  43.       cpath:=path {GetCurrentDir+'\';};
  44.       nfiles:=findfirst(cpath + '*.*', faanyfile, search);
  45.  
  46.       if nfiles=0 then
  47.       begin
  48.  
  49.         if search.Attr = fadirectory then
  50.         begin
  51.         repeat
  52.         memo1.Lines.Add(search.Name);      // FUNCIONA
  53.         if (search.Name<>'.') and (search.Name<>'..') then
  54.  
  55.           begin
  56.               setfileattributes(Pchar(cpath+search.Name), FILE_ATTRIBUTE_NORMAL);
  57.               ChangeAttributes(path + search.Name + '\');
  58.  
  59.           end;
  60.           until (FindNext(search) <> 0);
  61.  
  62.         end
  63.         else
  64.         repeat
  65.         SetFileAttributes(PChar(cPath + search.Name),FILE_ATTRIBUTE_NORMAL);
  66.         ChangeAttributes(path + search.Name + '\');
  67.  
  68.         until FindNext(search) <> 0;
  69.         nFiles:=FindNext(Search);
  70.         end;
  71.  
  72.         SysUtils.FindClose(search);
  73.         end;
  74.  
  75. begin
  76. begin
  77.   button1.Enabled:=false; // AL INICIAR PROCESO EL BOTON SE DESHABILITA
  78.  
  79.   Form2:= Tform2.Create(Self);
  80.   Form2.Show;
  81.   end;
  82.     ChangeAttributes(GetCurrentDir+'\');
  83.     begin
  84.       button1.Enabled:=true;  // AL ACABAR PROCESO EL BOTON SE HABILITA
  85.  
  86.       form2.Close;
  87.       end;
  88. end;
  89. end.



Como ven este es un pequeño avance que he hecho..... pero me gustaría saber su opinión
si esta bien o esta mal........ lo he probado y cumple con mis expextativas.

PD: tal vez sea mejor un sólo "repeat" pero estoy viendo como cuadrarlo.....
y sobre la pregunta anterior.... lo que me parecía raro es en que momento el nfiles equivale a otro valor en vez de cero ..... pues parece que siempre es el valor 0.....

Discupen si les quito tiempo ......


  • 0

#29 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 09 noviembre 2011 - 12:57

Bueno después de tanto y tanto probar resulta que del primer ejemplo que me guié....(y del cual partió todo)
al final lo pude acoplar a mi proyecto... y el código es este (Más limpio):



delphi
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.       Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, windows ;
  9. type
  10.  
  11.   { TForm1 }
  12.  
  13.   TForm1 = class(TForm)
  14.     Button1: TButton;
  15.     Edit1: TEdit;
  16.     Label1: TLabel;
  17.     Memo1: TMemo;
  18.     StaticText1: TStaticText;
  19.     procedure Button1Click(Sender: TObject);
  20.   private
  21.     { private declarations }
  22.   public
  23.     { public declarations }
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TForm1 }
  34.  
  35. procedure TForm1.Button1Click(Sender: TObject);
  36.   procedure ChangeAttributes(const path:String);
  37.       var
  38.           search : TSearchRec;
  39.           nFiles : integer;
  40.           cPath : String;
  41.       begin
  42.       application.ProcessMessages;    // ESTE HACE QUE NO SE CUELGUE EL PROGRAMITA... JEEEEE
  43.       cpath:=path {GetCurrentDir+'\';};
  44.       nfiles:=findfirst(cpath + '*.*', faanyfile, search);
  45.  
  46.       while nfiles = 0 do
  47.       begin
  48.  
  49.         if search.Attr = fadirectory then
  50.         begin
  51.         if (search.Name<>'.') and (search.Name<>'..') then
  52.  
  53.           begin
  54.                 setfileattributes(Pchar(cpath+search.Name), FILE_ATTRIBUTE_NORMAL);
  55.                 ChangeAttributes(path + search.Name + '\');
  56.           end;
  57.         end
  58.  
  59.         else
  60.  
  61.         begin
  62.         SetFileAttributes(PChar(cPath + search.Name),FILE_ATTRIBUTE_NORMAL);
  63.         ChangeAttributes(path + search.Name + '\');
  64.         end;
  65.  
  66.         nFiles:=FindNext(Search);
  67.         end;
  68.  
  69.         SysUtils.FindClose(search);
  70.         end;
  71.  
  72. begin
  73.  
  74.     ChangeAttributes(GetCurrentDir+'\');
  75.  
  76. end;
  77. End.




Justo cuando estaba probando y probando resulta que le dí otra oportunidad y al volverlo
a probar ya recién me funcionó todo..... les cuento que de ese ejemplo me guié al principio
pero como a la primera no me funciono (o me dió problemas) le tuve que hacer una que otra
modificación.... y el fruto de estas modificaciones fueron los pasos que publiqué en el foro
cuanta razón tienen al aconsejar que el código este siempre limpio.... ojala que ya no me de
problemas al menos por un tiempo......

PD: disculpen si lo vuelvo a repetir pero es que no me cuadra en que momento el valor
de "nfiles" cambia de 0 a otro valor, un amigo dijo que era por el "nFiles:=FindNext(Search);"
pero como lo veo pienso que el valor siempre será 0 (pués parece que siempre encontrará archivos)

perdonen si les incomodo....


  • 0

#30 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 09 noviembre 2011 - 03:01

disculpen si lo vuelvo a repetir pero es que no me cuadra en que momento el valor
de "nfiles" cambia de 0 a otro valor, un amigo dijo que era por el "nFiles:=FindNext(Search);"
pero como lo veo pienso que el valor siempre será 0 (pués parece que siempre encontrará archivos)


Digamos que FindNext va navegando dentro de una carpeta encontrando carpetas o archivos. Cuando ha terminado de navegar o de enumerar todas las carpetas y archivos ya no devuelve cero. Tras esto sale del bucle y hacemos un FindClose para cerrar "el sistema de búsqueda" que comenzara con un FindFirst.

La función es recursiva cuando encuentra una carpeta, saliendo al exlorarla para continuar su trabajo en la carpeta que previamente estaba.

Saludos.
  • 0

#31 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 259 mensajes

Escrito 09 noviembre 2011 - 06:08

Gracias por la aclaración amigo escafandra, ahora como que ya me cuadra un poco con tu explicación..... al paracer este será el final de este post..... no sin antes agradecerte a ti y a todos quienes desinteresadamente me dieron la mano.

Espero que a alguien tan principiante como yo le pueda servir toda esta info......... GRACIAS.  ;)
  • 0




IP.Board spam blocked by CleanTalk.