Ir al contenido


Foto

Solicito ayuda para crear un Thread para mover archivos entre dos pc´s


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

#1 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 14 mayo 2010 - 09:49

Pues eso amigos, estoy cerando un descendiente de TThread para mover archivos grandes entre dos pc's en red mediante carpetas compartidas, y requiero de su apoyo para ir creándolo, por el momento me gustaría me dieran una asesoría sobre cuál es la mejor manera para moverlos, me refiero en cuanto a seguridad y velocidad.

Gracias amigos y un saludo a todos.
  • 0

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 14 mayo 2010 - 09:53

Tienes un ejemplo en este hilo. Puede servirte para comenzar.

Saludos.
  • 0

#3 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 14 mayo 2010 - 09:55

Tienes un ejemplo en este hilo. Puede servirte para comenzar.

Saludos.


Eso me pasa por no buscar...

Bueno, cualquier cosa regreso a darles lata.

Muchas gracias.
  • 0

#4 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 14 mayo 2010 - 10:17

Ya ando leyendo algo sobre el copiado y viendo algunas funciones API, pero me gustaría hacer algo así...



delphi
  1. funcion MueveArchivo(Origen, Destino: string):Integer;
  2. begin
  3.   Result:= 1;
  4.   if Existe Origen y NoEstaBloqueado(Origen) then
  5.     Copia(Origen, Destino)
  6.   else
  7.     Exit;
  8.   if not Existe(Destino) then
  9.   begin
  10.     Result:= 2;
  11.     Exit
  12.   end;
  13.   if Borrar(Origen) = ok then
  14.     Result:= 0
  15.   else Result:= 3
  16. end;



Disculpen mi pseudocódigo, pero creo que se entiende... bueno pues necesito una función que me mueva el archivo, pero me regrese un valor de retorno para saber si falló y en qué y necesito saber si el archivo origen no está bloqueado o siendo usado apenas creado por la aplicación que lo genera y de ser posible, alguna forma de saber que la copia fue fiel...

Gracias y de nuevo discúlpenme por ser tan latoso
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 14 mayo 2010 - 10:28

Trata de mirar la API CopyFileEx

Saludos.
  • 0

#6 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 14 mayo 2010 - 10:41

Precisamente eso estaba leyendo, CopyFileEx y MoveFileEx en la ayuda de delphi 7 en Windows SDK, claro que sirven para mi propósito, pero mi pregunta es la siguiente:

¿cómo puedo saber si el archivo no está siendo apenas creado por la aplicación que lo genera? Porque como son archivos un poco grandes (imágenes de 3 a 30 Mb) me he fijado en el explorador de windows que primero aparece el archivo con 0 kb actualizo el explorador con F5 y veo como va creciendo el archivo hasta que llega a su tamaño final, supongo que ese tiempo que el archivo va creciendo la aplicación que lo genera lo tiene bloqueado de alguna manera y si no lo tiene bloqueado como puedo saber cuando ha llegado a su tamaño máximo para llevar al cabo la operación de copiado de la imagen final o definitiva y borrar la original.

Gracias por tan prontas respuestas escafandra, te debo unas  (b)
  • 0

#7 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 14 mayo 2010 - 01:19

¿cómo puedo saber si el archivo no está siendo apenas creado por la aplicación que lo genera?


Se me ocurre intentar abrirlo de manera exclusiva, si la otra aplicación lo tiene abierto la apertura fallara.

Algo así:


delphi
  1. function EstaEnUso(Ruta: String): Boolean;
  2. var
  3.   Handle: Integer;
  4. begin
  5.   Handle:= FileOpen(Ruta,fmOpenRead or fmShareExclusive);
  6.   if Handle < 0 then
  7.   begin
  8.     Result:= TRUE;
  9.   end else
  10.   begin
  11.     CloseHandle(Handle);
  12.     Result:= FALSE;
  13.   end;
  14. end;



Aunque yo en estos casos prefiero comprobar ademas la fecha de modificación del fichero, si la otra aplicación lleva 5 segundos (o 30 depende de la aplicación) sin escribir en el archivo considero que ya no va a escribir mas.



delphi
  1. function EstaEnUso(Ruta: String): Boolean;
  2. var
  3.   Handle: Integer;
  4. begin
  5.   Handle:= FileOpen(Ruta,fmOpenRead or fmShareExclusive);
  6.   if Handle < 0 then
  7.   begin
  8.     Result:= TRUE;
  9.   end else
  10.   begin
  11.     CloseHandle(Handle);
  12.     Result:= FALSE;
  13.   end;
  14. end;
  15.  
  16. function GetFileModifyDate(FileName: string): TDateTime;
  17. var
  18.   SearchRec: TSearchRec;
  19. begin
  20.   if FindFirst(Filename,faAnyFile,SearchRec) = 0 then
  21.     Result:= FileDateToDateTime(SearchRec.Time)
  22.   else
  23.     Result:= 0;
  24.   FindClose(SearchRec);
  25. end;
  26.  
  27. function EstaEnUso2(Ruta: String): Boolean;
  28. begin
  29.   Result:= EstaEnUso(Ruta);
  30.   if not Result then
  31.     Result:= (Now - GetFileModifyDate(Ruta)) < EncodeTime(0,0,5,0);
  32. end;
  33.  
  34. // Por ejemplo
  35. ShowMessage(BoolToStr(EstaEnUso2('c:\archivo.txt'),TRUE));


  • 0

#8 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 14 mayo 2010 - 02:36

Me gustan ambs soluciones amigo aeoane...

por el momento llevo lo siguiente a manera de prueba a ver que les parece:



delphi
  1. unit Unit2;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, Messages, Windows;
  7.  
  8. type
  9.   TestThread = class(TThread)
  10.   private
  11.     { Private declarations }
  12.     FSource, FDestiny: string;
  13.     FErrorCode: Integer;
  14.     function ThMoveFile(Source, Destiny: string): Integer;
  15.     function FCopy(Source, Destiny: string): Boolean;
  16.   public
  17.     constructor Create(ASource, ADestiny: string); reintroduce; overload;
  18.     procedure Execute; override;
  19.   protected
  20.   end;
  21.  
  22. implementation
  23.  
  24. uses SysUtils, Unit1;
  25.  
  26. { TestThread }
  27.  
  28. constructor TestThread.Create(ASource, ADestiny: string);
  29. begin
  30.   inherited Create(True);
  31.   FSource:= ASource;
  32.   FDestiny:= ADestiny;
  33.   FreeOnTerminate:= True
  34. end;
  35.  
  36. function TestThread.FCopy(Source, Destiny: string): Boolean;
  37. var
  38.   S, D: TFileStream;
  39. begin
  40.   Result:= True;
  41.   try
  42.     s:= TFileStream.Create(Source, fmOpenRead + fmShareExclusive);
  43.     try
  44.       D:= TFileStream.Create(Destiny, fmCreate);
  45.       try
  46.         D.CopyFrom(S, S.Size);
  47.       finally
  48.         D.Free;
  49.       end;
  50.     finally
  51.       S.Free
  52.     end
  53.   except
  54.     Result:= False
  55.   end
  56. end;
  57.  
  58. function TestThread.ThMoveFile(Source, Destiny: string):Integer;
  59. begin
  60.   Result:= 1;
  61.   if not FileExists(Source) then Exit;
  62.   Result:= 2;
  63.   if not DirectoryExists(ExtractFileDir(Destiny)) then Exit;
  64. /////////////  Copiar archivo  ///////////////////////////
  65.   Result:= 3;
  66.   SendMessage(Form1.Handle, WM_USER + 100, 0, Integer(PChar('Iniciando copia')));
  67.   if not CopyFile(PChar(Source), PChar(Destiny), False) then Exit;
  68. /////////////  Verificar copia ///////////////////////////
  69.   Result:= 4;
  70.  
  71.   Result:= 5;
  72.   if not FileExists(Source) then Exit;
  73.   Result:= 6;
  74.   if not DeleteFile(PChar(Source)) then Exit;
  75.   Result:= 0
  76.  
  77.   // Verificar que exista el archivo origen
  78.   // Verificar que exista el directorio destino
  79.   // Copiar archivo
  80.       // Si no lo copia enviar ERROR y SALIR
  81.   // Archivo copiado, se continua
  82.   // Verificar archivo copiado
  83.       // Hay problemas con el archivo copiado ERROR y SALIR
  84.   //  Todo OK con el archivo Destino
  85.   //  Borrar el archivo Destino
  86.       //  No se borro ERROR SALIR
  87.   //  Si se borró EXITO TOTAL valor de retorno 0
  88.  
  89.  
  90. end;
  91.  
  92. procedure TestThread.Execute;
  93. begin
  94.   FErrorCode:= ThMoveFile(FSource, FDestiny);
  95.   SendMessage(Form1.Handle,  WM_SETTEXT, 0, Integer(PChar('Salida = ' + IntToStr(FErrorcode))))
  96. end;
  97.  
  98. end.



He usado mensajes estándar de windows para comunicarme por el momento con el form principal y utilizé el método FCopy que saqué de alguna web también para hacer pruebas...

La función que mueve le puse un valor de retorno porque necesito saber exactamente lo que sucede en caso de que no se se obtenga éxito total.

Gracias por su apoyo y saludos
  • 0

#9 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 17 mayo 2010 - 08:53

De nuevo en el trabajo, ya voy avanzando, ahora necesito un thread que gestione los threads que realizan el copiado y borrado de archivos, para lo que necesito que los threads que copian se comuniquen con el thread principal, la pregunta es: ¿es conveniente usar mensajes de Windows para llevar al cabo esta comunicación? he probado los mensajes entre el thread de copiado y el form principal de mi aplicación, y va de maravilla, ¿lo recomiendan?

Más o menos algo así



delphi
  1. type
  2.   TMainTh = class(TThread)
  3.   private
  4.     { Private declarations }
  5.     FSource, FTarget: string;
  6.     FMaxThreads: Integer;
  7.     procedure OnNewThread(var Msg: TMessage); message TM_NEWTHREAD;
  8.     procedure OnDieThread(var Msg: TMessage); message TM_DIETHREAD;
  9.     procedure OnErrThread(var Msg: TMessage); message TM_ERRTHREAD;
  10.   protected
  11.     procedure Execute; override;
  12.   end;



Claro, con su respectivo código en implementation.

Gracias por su apoyo camaradas.  (y)
  • 0

#10 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 17 mayo 2010 - 09:49

...¿es conveniente usar mensajes de Windows para llevar al cabo esta comunicación? he probado los mensajes entre el thread de copiado y el form principal de mi aplicación, y va de maravilla, ¿lo recomiendan?


Es una forma bastante común para controlar lo que pasa en el thread que éste envía mensajes a una ventana o formulario. También se pueden mandar mensajes al Thread con PostThreadMessage. Otro truco puede ser el uso de una variable global. Creo que lo mejor son los mensajes.

Saludos.
  • 0

#11 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 17 mayo 2010 - 10:07

...¿es conveniente usar mensajes de Windows para llevar al cabo esta comunicación? he probado los mensajes entre el thread de copiado y el form principal de mi aplicación, y va de maravilla, ¿lo recomiendan?


Es una forma bastante común para controlar lo que pasa en el thread que éste envía mensajes a una ventana o formulario. También se pueden mandar mensajes al Thread con PostThreadMessage. Otro truco puede ser el uso de una variable global. Creo que lo mejor son los mensajes.

Saludos.


Eso me tranquiliza, ya llevo algo avanzado con los mensajes, he leido sobre SendMesage del API de Windows y PostThreadMessage, y tengo algunas dudillas (si, ya sé, ahí voy de nuevo), al diferencia entre ambas es clara, SendMessage espera a que sea procesado el mensaje y PosThreadMessage no se espera ¿cúal de los dos es mejor para el uso que les estoy dando? y la otra duda es PostThreadMessage recibe como primer parámetro idThread, ¿es este el handle del Thread?

Gracias por tu respuesta escafandra y prometo seguir molestando hasta aclarar mis dudas.
  • 0

#12 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 17 mayo 2010 - 11:58

...SendMessage espera a que sea procesado el mensaje y PosThreadMessage no se espera ¿cúal de los dos es mejor para el uso que les estoy dando?


Por el contexto de tu pregunta creo que confundes PostMessage con PosThreadMessage. Ninguno de los dos espera contestación, pero mientras que PostMessage envía un mensaje a una ventana PosThreadMessage lo hace a un Thread. Si es mejos esperar o no depende de cada caso en particular. Ten encuenta que algunos mensajes devuelven un resultado. SendMessage devuelve un LRESULT.

... otra duda es PostThreadMessage recibe como primer parámetro idThread, ¿es este el handle del Thread?


El idThread es el identificador del Thread, es un entero no un Handle. En la clase TThread es el miembro ThreadID.

Saludos.
  • 0

#13 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 17 mayo 2010 - 04:21

Estoy probando el envío de mensajes entre threads y el form principal, pero si envío el mensaje:



delphi
  1. SendMessage(Form1.Handle,  WM_MYERROR, 0, Integer(PChar('Salida = ' + IntToStr(FErrorcode))))



Al capturar el evento en Form1, como saco de regreso el texto que introduje en lParam del mensaje, es un puntero, ¿pero como le hago? eso lo vi en un ejemplo.

Gracias

  • 0

#14 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 17 mayo 2010 - 04:33



delphi
  1. PCHAR(lParam);



Saludos.
  • 0

#15 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 18 mayo 2010 - 08:12

Tan fácil y yo que ya había probado mil y un cosas excepto esta...

Gracias de nuevo
  • 0

#16 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 18 mayo 2010 - 11:13

Ya regresé con más dudas...

Ahora lo siguiente: envío de un thread a otro thread un mensaje con SendMessage y PostThreadMessage y pareciera que no le llegan...

¿Qué puede ser, lo estaré escribiendo mal?

Ahí va un poco de código:



delphi
  1. SendMessage(FMainThHandle, TM_NEWTHREAD, Integer(PChar(Source)), Self.Handle);


Este mensaje es enviado desde un thread a otro thread. Donde FMainThHandle es el Handle del Thread destino, Self.Handle es el Handle del emisor, esto lo hago por motivos informativos.

FMainThHandle recibe y procesa el mensaje en:



delphi
  1. type
  2.   TMainTh = class(TThread)
  3.   private
  4.     { Private declarations }
  5.     ...
  6. //  Mensajes provenientes de los threads de copiado
  7.     procedure OnNewThread(var Msg: TMessage); message TM_NEWTHREAD;



Aquí esta en la declaración del thread receptor como capturo el mensaje y en la implementación su código.

Pero pareciera que el thread receptor no recibe los mensajes que envío del thread emisor con SendMessage, o el thread receptor no los recibe de la manera en que estoy implementando para recibir el mensaje, seguro estoy haciendo algo mal...  :angry:

Ayuda por favor..  :cheesy:
  • 0

#17 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 18 mayo 2010 - 03:47

SendMessage Sirve para enviar mensajes a una ventana, su primer parámetro es HWND (Handle de ventana) Un thread nunca recibirá un Mensaje así.

Para enviar un Mensaje a un thread debes usar PostThreadMessage, pero no basta. Debes implementar un bucle de mensajes en el thread que los gestione. Te pongo un ejemplo sobre tu código:



delphi
  1. type
  2.   TMainTh = class(TThread)
  3.   private
  4.     { Private declarations }
  5.     ...
  6. //  Mensajes provenientes de los threads de copiado
  7.     procedure OnNewThread(var Msg: TMessage);





delphi
  1. procedure TMainTh.Execute;
  2.   var Msg: TMsg;
  3. begin
  4.   while (not Terminated) do
  5.   begin
  6.     if PeekMessage(Msg,0,0,0,PM_REMOVE) then
  7.     begin
  8.       if(Msg.message = WM_QUIT) then
  9.           Terminate;
  10.       if (Msg.message = TM_NEWTHREAD) then
  11.           OnNewThread(var Msg: TMessage);
  12.     end;
  13.   end;
  14. end;



Irías implementando todas las respuestas a los mensajes.

En delphi es mas fácil mandar un mensaje desde un thread a un Form que al revés. Tienes otras formas de comunicarte con el Thread como funciones miembro del mismo y Variables globales pero en este caso no te olvides de usar el método Synchronize.

Saludos.
  • 0

#18 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 18 mayo 2010 - 04:07

Ah, muchas gracias...

Sabía que algo estaba haciendo mal, pero no que, con esto ya tengo otro avance.

Gracias de nuevo.  (y)
  • 0

#19 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 19 mayo 2010 - 02:52

Quisiera dejar este enlace de un buen tutorial para trabajar con threads en delphi, que es extensible al Builder: Multithreading - The Delphi Way.

Saludos.
  • 0

#20 Faust

Faust

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 213 mensajes
  • LocationDistrito Federal

Escrito 20 mayo 2010 - 10:54

Gracias por el link, también he estado leyendo algunos artículos de http://www.rinconcit...s/articulos.htm que están buenos.
  • 0




IP.Board spam blocked by CleanTalk.