[MULTILENGUAJE] Copiar múltiples archivos y carpetas.

On miércoles, 8 de diciembre de 2010 0 comentarios

 La copia de carpetas puede hacerse de una forma recursiva como los ejemplos mostrados en este hilo o usando las Shell Functions de windows. Este truco se basa en este segundo sistema, conocido, pero a veces poco entendido.

La API de Windows permite realizar esta tarea con SHFileOperation. Vamos a usar esa función a la que le pasaremos una lista de archivos de origen y una carpeta de destino.

Según la ayuda MSDN esa lista debe pasarse como un conjunto de cadenas seguidas separadas por un caracter nulo y terminada en un doble nulo. La cadena de la ruta de destino sigue la misma regla, pero en esta ocasión será una sola cadena.

La lista de archivos y/o carpetas se le pasa como una lista tipo TStrings. La función crea la carpeta de destino y en ella copia los elementos fuente.

Veamos los ejemplos de código en C/C++ y en delphi:

Comenzamos con C/C++:

Código: [Seleccionar]
#include 
 
// Crea una carpeta y las subcarpetas de una ruta dada
void CreatePath(char* Path)
{
   int l = strlen(Path);
   char* fin = Path;
   do{
     if(*fin && *fin != '\\') continue;
     *fin = 0;
     CreateDirectory(Path, 0);
     if(l) *fin = '\\';
   }while(*fin++ && l--);
}
 
// Copia una lista de archivos y/o Carpetas en una carpeta destino dada
int XCopy(HWND hWnd, TStrings *From, String To)
{
  if(!From || To=="") return -1;
 
  CreatePath(To.c_str());
 
  // uso un caracter \255 como paso intermedio luego lo sustituiré por nulos
  String sFrom = StringReplace(From->Text, "\r\n", "\255", TReplaceFlags()<) + "\255";
  for(int i=1; i<=sFrom.Length(); i++) if(sFrom[i] == '\255') sFrom[i] = 0;
  To.SetLength(To.Length()+1); To[To.Length()]='\0';
 
  SHFILEOPSTRUCT FS;
  ZeroMemory(&FS, sizeof(SHFILEOPSTRUCT));
  FS.hwnd = hWnd;
  FS.wFunc = FO_COPY;
  FS.pFrom = sFrom.c_str();
  FS.pTo =   To.c_str();;
  FS.fFlags = FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION; 
  return SHFileOperation(&FS);
}
 

Un ejemplo de uso:
Código: [Seleccionar]
 TStrings *From = new TStringList;
  From->Add("C:\\AEAT\\Renta2009\\.install4j"); // Carpeta fuente
  From->Add("C:\\AEAT\\Renta2009\\CloudScape"); // Carpeta fuente
  From->Add("C:\\AEAT\\Renta2009\\derby.log");  // Archivo fuente
  XCopy(Handle, From, "F:\\Prueba\\Mio\\fin");  
  delete From;
 


Ahora voy a colocar el mismo código en delphi:
Código: [Seleccionar]
uses ShellApi;
 
// Crea una carpeta y las subcarpetas de una ruta dada
procedure CreatePath(Path: string);
var
  l, fin: integer;
begin
   l:= Length(Path);
   fin:= 0;
   repeat
     if (Path[fin] = '\') or (l = 0) then
     begin
       if l>0 then Path[fin]:= #0;
       CreateDirectory(PCHAR(Path), 0);
       if l>0 then Path[fin]:= '\';
     end;
     inc(fin); dec(l);
   until (l<0);
end;
 
 
// Copia una lista de archivos y/o Carpetas en una carpeta destino dada
function XCopy(Handle: HWND; From: TStrings; Dest: String): integer;
var
  FS: SHFILEOPSTRUCT;
  SFrom: string;
begin
  Result:= -1;
  if(From.Count > 0) or (Dest <> '') then
  begin
    CreatePath(PCHAR(Dest));
    SFrom:= StringReplace(From.Text, #13+#10, #0, [rfReplaceAll]);
 
    ZeroMemory(@FS, sizeof(SHFILEOPSTRUCT));
    FS.wnd:= Handle;
    FS.wFunc:= FO_COPY;
    FS.pFrom:= PCHAR(SFrom + #0);
    FS.pTo:=   PCHAR(Dest + #0);
    FS.fFlags:= FOF_NOCONFIRMMKDIR or FOF_NOCONFIRMATION;
 
    Result:= SHFileOperation(FS);
  end;
end;
 

Y un ejemplo de uso:
Código: [Seleccionar]
var
  From: TStrings;
begin
   From:= TStringList.Create;
   From.Add('C:\AEAT\Renta2009\.install4j'); // Carpeta fuente
   From.Add('C:\AEAT\Renta2009\CloudScape'); // Carpeta fuente
   From.Add('C:\AEAT\Renta2009\derby.log');  // Archivo fuente
   XCopy(Handle, From, 'F:\Prueba\Mio\fin'); 
   From.Free;
end;
 

Espero que el código sea claro y os sea de utilidad.


Saludos.

0 comentarios:

Publicar un comentario