none
Pasar archivos de una carpeta(Origen) a otra(Destino) al llegar a un limite de peso usando timer RRS feed

  • Pregunta

  • Buenas a todos, luego de dos días buscando ejemplos en Microsoft, se me hace un poco complicado ver como aplicarlo a lo que busco.

    Vamos a ver si me explico bien, 

    Lo que deseo es una aplicación que detecte cuando ocurra algo dentro de una carpeta (un directorio asignado previamente) y enviar varios archivos o los que existan a otra carpeta destino, pero solo cuando supere la carpeta origen un peso.

    Ejemplo, que cuando la carpeta origen pese 500 megas, no acepte mas archivos, sino que pase todos los que existen en la carpeta origen los envié a la otra dejando la carpeta origen en cero nuevamente.

    Ahora mismo mi aplicación detecta cuando hay archivos, ya sea para crear, modificar o eliminar y envía el archivo a la otra carpeta (aunque solo funciona enviando un archivo, no varios, tampoco calcula peso, porque sinceramente no entiendo como hacerlo, ya que los ejemplos que he visto no he sabido adaptarlos).

    Entonces tengo dos dudas para el que desee orientarme o ayudarme.

    1.¿Como puedo hacer para saber si llegado a un peso inicial(500 megas), envié todos los archivos existente en la carpeta origen a la carpeta destino?

    2. Quiero aplicarle un temporizador ej. de 3 minutos, antes de enviar los archivos, ya que me da el error de "No se puedo encontrar el archivo o el archivo esta ocupado por otro proceso" del System.IO.FileNotFoundException. Creo que es por el hecho de que cuando el pasa algo, si el archivo es pesado o son varios, requiere tiempo para que se descargue en la carpeta, entonces mi código ahora mismo es automático, no toma en cuenta esperar a que el/los archivos se descarguen en la carpeta para enviarlos a otra y de allí mi necesidad de usar un timer.

    Ej. usar un timer que cuando haya un cambio en la carpeta (Origen) el timer cuente 3 minutos y al finalizar, pase todos los archivos en la carpeta a la otra.

    Esto es lo que he hecho hasta ahora en una sola clase.

    using System;
    using System.IO;
    using System.Timers;
    using System.Threading;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        class Program
        {
    
    
            private static System.Timers.Timer aTimer;
    
            static void Main(string[] args)
            {
    
                FileSystemWatcher observador = new FileSystemWatcher(@"C:\Temporal");
                observador.NotifyFilter = (
    
                    NotifyFilters.LastAccess |
                    NotifyFilters.LastWrite |
                    NotifyFilters.FileName |
                    NotifyFilters.DirectoryName);
    
                
                observador.Changed += AlCambiar;
                observador.Created += AlCambiar;
                observador.Deleted += AlCambiar;
                observador.Renamed += new RenamedEventHandler(AlRenombrar);
                observador.Error += AlOcurrirUnError;
    
                observador.EnableRaisingEvents = true;
                Console.WriteLine("Presiona <Enter> para detener el monitor de archivos");
                Console.ReadLine();
    
            }
    
    
            private static void AlCambiar(object source, FileSystemEventArgs e) {
    
    
            /*
                // Create a timer with a two second interval.
                aTimer = new System.Timers.Timer(1000);
                // Hook up the Elapsed event for the timer. 
                aTimer.Elapsed += OnTimedEvent;
                aTimer.AutoReset = true;
                aTimer.Enabled = false;
             */
    
                WatcherChangeTypes tipoDeCambio = e.ChangeType;
                Console.WriteLine("El archivo {0} tuvo un cambio de : {1}",
                    e.FullPath, tipoDeCambio.ToString() );
    
                FileInfo file = new FileInfo(e.FullPath);
                //Console.WriteLine(file.Name); // esto es lo que estoy buscando.
    
                string RutaArchivo = @"C:\TEMPORAL\"+file.Name;
                string RutaDestino = @"C:\Destino\"+file.Name;
    
                FileInfo files = new FileInfo(@"C:\TEMPORAL\" + file.Name);
                var f = files.Length;
                Console.WriteLine("Detalles del archivo:" + f.ToString() + "", "DETALLE");
    
    
                if (File.Exists(@"C:\TEMPORAL\"+file.Name) )
                {
                    if (File.Exists(@"C:\Destino\"+file.Name))
                    {
                        System.IO.File.Delete(RutaDestino);
                    }
    
    
                    //DirectoryInfo di_origen = new DirectoryInfo(@"C:\TEMPORAL\");
                    //DirectoryInfo di_destino = new DirectoryInfo(@"C:\Destino\");
    
                    System.IO.File.Move(RutaArchivo,RutaDestino);
                    //CopyFilesRecursively(di_origen, di_destino);
    
                }
               
            }
    
    
            private static void OnTimedEvent(Object source, ElapsedEventArgs e)
            {
                Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
                                  e.SignalTime);
            }
    
    
            private static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
            {
                
                foreach (DirectoryInfo dir in source.GetDirectories())
                {
                    CopyFilesRecursively(dir,
                    target.CreateSubdirectory(dir.Name));
                }
                
    
                foreach (FileInfo file in source.GetFiles())
                {
                    file.CopyTo(Path.Combine(target.FullName, file.Name));
                }
            }
      
    
            private static void AlRenombrar(object source, RenamedEventArgs e){
    
                Console.WriteLine("El archivo {0} ahora se llama {1}",
                e.OldFullPath, e.FullPath);
    
            }
    
            private static void AlOcurrirUnError(object source, ErrorEventArgs e){
                Console.WriteLine("Error:" + e.GetException().Message);
            }
        }
    }

    Cualquier ayuda o aporte se los agradecería o explicación se los agradecería. Muchas gracias.



    • Editado H E Ruiz martes, 18 de septiembre de 2018 23:26
    martes, 18 de septiembre de 2018 23:03

Respuestas

  • hola

    El codigo que tienes implementado usando el FileSystemWatcher es correcto porque este lanzara un evento que puedes usar para evalar el tamaño de la carpeta

    Lo que si es incorrecto que todos los eventos lances el AlCambiar, eso es incorrecto, porque cuando mueves un archivo tambien tendras ese evento

    Quita el evento Delete del FileSystemWatcher

    saldos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 13:55
  • hola

    >>cómo corrijo que me diga System.IO.FileNotFoundException.el archivo esta ocupado por otro proceso ?

    esto se puede deber a que mas de un evento se genera al mismo tiempo y quiere realizar operacion sobre el mismo archivo

    intenta solo dejando el evento Created, pero verifica si no se ejecute mas de una vez, si lo hace al comienzo del evento Created  desasocialo usando

     observador.Created -= AlCambiar;

    y cuando termine lo vuelves asignar usando el +=

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 15:48
  • tienes que copiar de forma recursiva

    How to: Copy Directories

    analiza el ejempl del articulo


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 17:44
  • Muchas gracias por su respuesta, voy a realizarlo.

    ¿ y cómo corrijo que me diga System.IO.FileNotFoundException.el archivo esta ocupado por otro proceso ?

    ¿Usted cree que si logro retrasar el proceso con un timer, es decir que cuando llame AlCambiar no lo haga inmediatamente detecte el cambio ya que puede ser que el archivo todavía se este pasando y por eso no pueda enviarlo a la otra carpeta?

    algo así como un timer que a los 6 segundos de detectar un change 
    observador.Changed += AlCambiar;

    ejecute la acción y no inmediatamente...

    Porque creo que el problema es que si subes algo de 60 megas por ejemplo, el no se subirá automáticamente a la carpeta sino que cuando se complete las 60 megas es que supongo que se puede copiar a otro lado, pero al hacer change lo mando a mover automáticamente a la otra carpeta cuando apenas se esta pasando... No se si me explico?

    Estaré errado y el error es por algo mas?

    Muchas gracias por su ayuda



    • Editado H E Ruiz miércoles, 19 de septiembre de 2018 15:42
    • Marcado como respuesta Pablo RubioModerator lunes, 24 de septiembre de 2018 15:23
    miércoles, 19 de septiembre de 2018 15:39
  • Muchas gracias amigo Leando Tuttini

    Todavía no esta totalmente resuelto pero si he avanzado bastante ya que con tus explicaciones y correcciones me hiciste entender realmente lo que estaba haciendo y no copiar y pegar código sin entenderlo a profundidad. 

    he hecho algunas modificaciones y ahora según el peso en la carpeta origen, cuando este es igualado o sobrepasado envía todos los archivos a la carpeta destino

    Hasta ahora esto es lo que he hecho.

    "Lo de arriba sigue igual, solo deje el observador.Created -= AlCambiar;"

    Solo cambie el AlCambiar, quedando de momento así

     private static void AlCambiar(object source, FileSystemEventArgs e)
            {
    
                DirectoryInfo di = new DirectoryInfo(@"C:\TEMPORAL");
                // toma como referencia los archivos dentro de la carpeta.
                FileInfo[] fiArr = di.GetFiles();
    
                // muestra los nombres y el peso de los archivos contenidos.
                Console.WriteLine("The directory {0} contains the following files:", di.Name);
                foreach (FileInfo f in fiArr)
                {
                    Console.WriteLine("The size of {0} is {1} bytes.", f.Name, f.Length);
                    count += f.Length;
                }
    
                Console.WriteLine("estamos en CREATE "+ count);
    
    
                //500000000 son 500 megabytes en bytes
                if (count >= 5000000){
    
                    DirectoryInfo dir = new DirectoryInfo(@"C:\TEMPORAL");
                    // toma como referencia los archivos dentro de la carpeta.
                    FileInfo[] fiArre = dir.GetFiles();
    
                    // muestra los nombres y el peso de los archivos contenidos.
                    Console.WriteLine("The directory {0} contains the following files:", dir.Name);
                    foreach (FileInfo fe in fiArre)
                    {
                        string RutaArchivo = @"C:\TEMPORAL\" + fe.Name;
                        string RutaDestino = @"C:\Destino\" + fe.Name;
    
                        if (File.Exists(@"C:\TEMPORAL\" + fe.Name))
                        {
    
                            if (File.Exists(@"C:\Destino\" + fe.Name))
                            {
                                System.IO.File.Delete(RutaDestino);
                            }
    
                            System.IO.File.Move(RutaArchivo, RutaDestino);
                        }
    
                    }
    
                    count = 0;
    
                   
                }
    
            }

    Ahora me faltaría ver como envió carpetas con sus subcarpetas y archivos, (esto si suena muy complejo) ya que solo envía archivos, ademas de que me da error con vídeos y audios, solo sirve con archivos e imágenes en la raíz de la carpeta origen, por el momento.

    Que podría hacer?, hay alguna función o algo que pueda serme de utilidad para investigar sobre eso?

    Muchas gracias por su ayuda y la del que quiera aportar, así quedaría un código mas robusto que cualquiera acá pueda darle uso y modificar a su gusto.

    miércoles, 19 de septiembre de 2018 17:28
  • Muchas gracias, de momento me sirve de esta manera, por si a alguien le sirve o desea mejorar el código.

    El envía todos los archivos cuando supera un limite de bytes la carpeta origen y los envía a una carpeta destino, pero por alguna razón siempre me deja un archivo sin enviar, pero para efectos de lo que busco en este programa me sirve igual ya que el archivo que deja en la próxima pasada se lo lleva, aunque lo ideal seria que dejara totalmente vacía la carpeta origen

    Esta es la llamada de la función sea en el main o dentro de un método.

    DirectoryCopy(@"C:\TEMPORAL", @"C:\Destino", true);


    ...y este es el método como va hasta el momento.

     private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
            {
                //Obtenga los subdirectorios para el directorio especificado.
                DirectoryInfo dir = new DirectoryInfo(sourceDirName);
                
    
                if (!dir.Exists)
                {
                    throw new DirectoryNotFoundException(
                        "El directorio de origen no existe o no se puede encontrar "
                        + sourceDirName);
                }
    
                DirectoryInfo[] dirs = dir.GetDirectories();
                //Si el directorio de destino no existe, créelo.
                if (!Directory.Exists(destDirName))
                {
                    Directory.CreateDirectory(destDirName);
                }
    
                //Obtenga los archivos en el directorio y cópielos a la nueva ubicación.
                FileInfo[] files = dir.GetFiles();
                foreach (FileInfo file in files)
                {
                    string temppath = Path.Combine(destDirName, file.Name);
                    string temppath2 = Path.Combine(sourceDirName, file.Name);
                    //Console.WriteLine(file.Name, file.Length);
                    file.CopyTo(temppath, false);
                    System.IO.File.Delete(temppath2);
                }
    
                //Si copia subdirectorios, cópielos y sus contenidos en una nueva ubicación.
                if (copySubDirs)
                {
                    foreach (DirectoryInfo subdir in dirs)
                    {
                        string temppath = Path.Combine(destDirName, subdir.Name);
                        string temppath2 = Path.Combine(sourceDirName, subdir.Name);
                        Console.WriteLine(subdir.FullName, temppath);
                        DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                        Directory.Delete(subdir.FullName);
                    }
                }
    
            }

    Hice una ultima prueba y ahora como cosa rara, si envío todos los archivos de la carpeta origen.

    Muchas gracias Leandro por encaminarme y ayudarme. Saludos Hermano.

    jueves, 20 de septiembre de 2018 20:53

Todas las respuestas

  • hola

    El codigo que tienes implementado usando el FileSystemWatcher es correcto porque este lanzara un evento que puedes usar para evalar el tamaño de la carpeta

    Lo que si es incorrecto que todos los eventos lances el AlCambiar, eso es incorrecto, porque cuando mueves un archivo tambien tendras ese evento

    Quita el evento Delete del FileSystemWatcher

    saldos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 13:55
  • Muchas gracias por su respuesta, voy a realizarlo.

    ¿ y cómo corrijo que me diga System.IO.FileNotFoundException.el archivo esta ocupado por otro proceso ?

    ¿Usted cree que si logro retrasar el proceso con un timer, es decir que cuando llame AlCambiar no lo haga inmediatamente detecte el cambio ya que puede ser que el archivo todavía se este pasando y por eso no pueda enviarlo a la otra carpeta?

    algo así como un timer que a los 6 segundos de detectar un change 
    observador.Changed += AlCambiar;

    ejecute la acción y no inmediatamente...

    Porque creo que el problema es que si subes algo de 60 megas por ejemplo, el no se subirá automáticamente a la carpeta sino que cuando se complete las 60 megas es que supongo que se puede copiar a otro lado, pero al hacer change lo mando a mover automáticamente a la otra carpeta cuando apenas se esta pasando... No se si me explico?

    Estaré errado y el error es por algo mas?

    Muchas gracias por su ayuda



    • Editado H E Ruiz miércoles, 19 de septiembre de 2018 15:42
    • Marcado como respuesta Pablo RubioModerator lunes, 24 de septiembre de 2018 15:23
    miércoles, 19 de septiembre de 2018 15:39
  • hola

    >>cómo corrijo que me diga System.IO.FileNotFoundException.el archivo esta ocupado por otro proceso ?

    esto se puede deber a que mas de un evento se genera al mismo tiempo y quiere realizar operacion sobre el mismo archivo

    intenta solo dejando el evento Created, pero verifica si no se ejecute mas de una vez, si lo hace al comienzo del evento Created  desasocialo usando

     observador.Created -= AlCambiar;

    y cuando termine lo vuelves asignar usando el +=

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 15:48
  • Muchas gracias amigo Leando Tuttini

    Todavía no esta totalmente resuelto pero si he avanzado bastante ya que con tus explicaciones y correcciones me hiciste entender realmente lo que estaba haciendo y no copiar y pegar código sin entenderlo a profundidad. 

    he hecho algunas modificaciones y ahora según el peso en la carpeta origen, cuando este es igualado o sobrepasado envía todos los archivos a la carpeta destino

    Hasta ahora esto es lo que he hecho.

    "Lo de arriba sigue igual, solo deje el observador.Created -= AlCambiar;"

    Solo cambie el AlCambiar, quedando de momento así

     private static void AlCambiar(object source, FileSystemEventArgs e)
            {
    
                DirectoryInfo di = new DirectoryInfo(@"C:\TEMPORAL");
                // toma como referencia los archivos dentro de la carpeta.
                FileInfo[] fiArr = di.GetFiles();
    
                // muestra los nombres y el peso de los archivos contenidos.
                Console.WriteLine("The directory {0} contains the following files:", di.Name);
                foreach (FileInfo f in fiArr)
                {
                    Console.WriteLine("The size of {0} is {1} bytes.", f.Name, f.Length);
                    count += f.Length;
                }
    
                Console.WriteLine("estamos en CREATE "+ count);
    
    
                //500000000 son 500 megabytes en bytes
                if (count >= 5000000){
    
                    DirectoryInfo dir = new DirectoryInfo(@"C:\TEMPORAL");
                    // toma como referencia los archivos dentro de la carpeta.
                    FileInfo[] fiArre = dir.GetFiles();
    
                    // muestra los nombres y el peso de los archivos contenidos.
                    Console.WriteLine("The directory {0} contains the following files:", dir.Name);
                    foreach (FileInfo fe in fiArre)
                    {
                        string RutaArchivo = @"C:\TEMPORAL\" + fe.Name;
                        string RutaDestino = @"C:\Destino\" + fe.Name;
    
                        if (File.Exists(@"C:\TEMPORAL\" + fe.Name))
                        {
    
                            if (File.Exists(@"C:\Destino\" + fe.Name))
                            {
                                System.IO.File.Delete(RutaDestino);
                            }
    
                            System.IO.File.Move(RutaArchivo, RutaDestino);
                        }
    
                    }
    
                    count = 0;
    
                   
                }
    
            }

    Ahora me faltaría ver como envió carpetas con sus subcarpetas y archivos, (esto si suena muy complejo) ya que solo envía archivos, ademas de que me da error con vídeos y audios, solo sirve con archivos e imágenes en la raíz de la carpeta origen, por el momento.

    Que podría hacer?, hay alguna función o algo que pueda serme de utilidad para investigar sobre eso?

    Muchas gracias por su ayuda y la del que quiera aportar, así quedaría un código mas robusto que cualquiera acá pueda darle uso y modificar a su gusto.

    miércoles, 19 de septiembre de 2018 17:28
  • tienes que copiar de forma recursiva

    How to: Copy Directories

    analiza el ejempl del articulo


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 19 de septiembre de 2018 17:44
  • Muchas gracias, de momento me sirve de esta manera, por si a alguien le sirve o desea mejorar el código.

    El envía todos los archivos cuando supera un limite de bytes la carpeta origen y los envía a una carpeta destino, pero por alguna razón siempre me deja un archivo sin enviar, pero para efectos de lo que busco en este programa me sirve igual ya que el archivo que deja en la próxima pasada se lo lleva, aunque lo ideal seria que dejara totalmente vacía la carpeta origen

    Esta es la llamada de la función sea en el main o dentro de un método.

    DirectoryCopy(@"C:\TEMPORAL", @"C:\Destino", true);


    ...y este es el método como va hasta el momento.

     private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
            {
                //Obtenga los subdirectorios para el directorio especificado.
                DirectoryInfo dir = new DirectoryInfo(sourceDirName);
                
    
                if (!dir.Exists)
                {
                    throw new DirectoryNotFoundException(
                        "El directorio de origen no existe o no se puede encontrar "
                        + sourceDirName);
                }
    
                DirectoryInfo[] dirs = dir.GetDirectories();
                //Si el directorio de destino no existe, créelo.
                if (!Directory.Exists(destDirName))
                {
                    Directory.CreateDirectory(destDirName);
                }
    
                //Obtenga los archivos en el directorio y cópielos a la nueva ubicación.
                FileInfo[] files = dir.GetFiles();
                foreach (FileInfo file in files)
                {
                    string temppath = Path.Combine(destDirName, file.Name);
                    string temppath2 = Path.Combine(sourceDirName, file.Name);
                    //Console.WriteLine(file.Name, file.Length);
                    file.CopyTo(temppath, false);
                    System.IO.File.Delete(temppath2);
                }
    
                //Si copia subdirectorios, cópielos y sus contenidos en una nueva ubicación.
                if (copySubDirs)
                {
                    foreach (DirectoryInfo subdir in dirs)
                    {
                        string temppath = Path.Combine(destDirName, subdir.Name);
                        string temppath2 = Path.Combine(sourceDirName, subdir.Name);
                        Console.WriteLine(subdir.FullName, temppath);
                        DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                        Directory.Delete(subdir.FullName);
                    }
                }
    
            }

    Hice una ultima prueba y ahora como cosa rara, si envío todos los archivos de la carpeta origen.

    Muchas gracias Leandro por encaminarme y ayudarme. Saludos Hermano.

    jueves, 20 de septiembre de 2018 20:53