2006-02-15

copiar ficheros en plan guay...

Bueno chicos, un amable señor del msdn magazine se ha dignado implementar en .net una llamada elegante a la función de windows CopyFileEx. La cosa no es fácil porque la función es ultra-guay: tiene para reanudar la copia desde donde falló y permite pasarle una función de callback a la que ella llama para informar del progreso de la copia (que nosotros no vamos a usar, pero molar, mola) y otras tremendas opciones.

Me he hecho una aplicacioncita de consola que va copiando un fichero e imprimiendo el progreso y la verdad es que mola; sería algo así:

class Class1
{

[STAThread]
static void Main(string[] args)
{
FileRoutines.CopyFile(new FileInfo(@"U:\Correo\P5567backup.pst"),

new FileInfo(@"\\vclsfls1\rpos\RPOS103\prueba\P5567.pst"),
CopyFileOptions.Restartable,
new CopyFileCallback(ActualizarProgresoDeCopia)); //este nosotros no lo usaremos, aunque mola!
}



public static CopyFileCallbackAction ActualizarProgresoDeCopia(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred)
{
Console.WriteLine("Bytes copiados: " + totalBytesTransferred.ToString());
return CopyFileCallbackAction.Continue;
}


}

He comprobado que, efectivamente, si lo cortas a la mitad (paras el programa) y luego simplemente vuelves a intentar la copia, el proceso continúa desde donde lo dejó.

Ahí va la clase "FileRoutines", muy elegantemente implementada...


public sealed class FileRoutines
{
public static void CopyFile(FileInfo source, FileInfo destination)
{
CopyFile(source, destination, CopyFileOptions.None);
}


public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options)
{
CopyFile(source, destination, options, null);
}


public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options, CopyFileCallback callback)
{
CopyFile(source, destination, options, callback, null);
}


public static void CopyFile(FileInfo source, FileInfo destination, CopyFileOptions options, CopyFileCallback callback, object state)
{
if (source == null) throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if ((options & ~CopyFileOptions.All) != 0)
throw new ArgumentOutOfRangeException("options");


new FileIOPermission(FileIOPermissionAccess.Read, source.FullName).Demand();
new FileIOPermission(FileIOPermissionAccess.Write, destination.FullName).Demand();


CopyProgressRoutine cpr = callback == null ? null : new CopyProgressRoutine(new CopyProgressData(source, destination, callback, state).CallbackHandler);

bool cancel = false;
if (!CopyFileEx(source.FullName, destination.FullName, cpr, IntPtr.Zero, ref cancel, (int)options))
{
throw new IOException(new Win32Exception().Message);
}
}


private class CopyProgressData
{
private FileInfo _source = null;
private FileInfo _destination = null;
private CopyFileCallback _callback = null;
private object _state = null;


public CopyProgressData(FileInfo source, FileInfo destination, CopyFileCallback callback, object state)
{
_source = source;
_destination = destination;
_callback = callback;
_state = state;
}


public int CallbackHandler(
long totalFileSize, long totalBytesTransferred,
long streamSize, long streamBytesTransferred,
int streamNumber, int callbackReason,
IntPtr sourceFile, IntPtr destinationFile, IntPtr data)
{
return (int)_callback(_source, _destination, _state, totalFileSize, totalBytesTransferred);
}
}


private delegate int CopyProgressRoutine(
long totalFileSize, long TotalBytesTransferred, long streamSize,
long streamBytesTransferred, int streamNumber, int callbackReason,
IntPtr sourceFile, IntPtr destinationFile, IntPtr data);

[SuppressUnmanagedCodeSecurity]
[DllImport("Kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool CopyFileEx(
string lpExistingFileName, string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
IntPtr lpData, ref bool pbCancel, int dwCopyFlags);
}


public delegate CopyFileCallbackAction CopyFileCallback(FileInfo source, FileInfo destination, object state, long totalFileSize, long totalBytesTransferred);

public enum CopyFileCallbackAction
{
Continue = 0,
Cancel = 1,
Stop = 2,
Quiet = 3
}


[Flags]
public enum CopyFileOptions
{
None = 0x0,
FailIfDestinationExists = 0x1,
Restartable = 0x2,
AllowDecryptedDestination = 0x8,
All = FailIfDestinationExists Restartable AllowDecryptedDestination
}


}

No hay comentarios: