Elimine archivos de más de 3 meses en un directorio usando .NET

117

Me gustaría saber (usando C #) cómo puedo eliminar archivos en un directorio determinado con más de 3 meses, pero supongo que el período de fecha podría ser flexible.

Para ser claros: estoy buscando archivos que tengan más de 90 días, en otras palabras, los archivos creados hace menos de 90 días deben conservarse y todos los demás deben eliminarse.

JL.
fuente
Si hay una cantidad importante de archivos, lo mejor es usar EnumerateFiles y EnumerateDirectories en lugar de GetFiles y GetDirectories, porque ejecutan directamente la enumeración en lugar de recopilar una lista. Sin embargo, tendrá que usar un bucle foreach.
Larry

Respuestas:

257

Algo como esto fuera de lugar.

using System.IO; 

string[] files = Directory.GetFiles(dirName);

foreach (string file in files)
{
   FileInfo fi = new FileInfo(file);
   if (fi.LastAccessTime < DateTime.Now.AddMonths(-3))
      fi.Delete();
}
Steve Danner
fuente
Gracias, noté que estás usando lastAccessTime, ¿es este el momento de creación?
JL.
10
no, como dice propertyNames: LastAccessTime- ¡debería ir a por una propiedad CreationTimesi lo desea!
Andreas Niedermair
4
Sí, la propiedad que use depende completamente de usted. También puede utilizar LastWriteTime si lo desea.
Steve Danner
3
+1 por ayudarme. En lugar de crear una nueva instancia de FileInfo, puede usar File.GetCreationTime o File.GetLastAccessTime. Debería ser una pequeña mejora de rendimiento.
Mario The Spoon
5
Supongo que GetFiles y Delete nunca fallan en su entorno. Solo señalando eso, ya que esta parece ser una respuesta muy referenciada.
Andrew Hagner
93

Aquí hay una lambda de 1 línea:

Directory.GetFiles(dirName)
         .Select(f => new FileInfo(f))
         .Where(f => f.LastAccessTime < DateTime.Now.AddMonths(-3))
         .ToList()
         .ForEach(f => f.Delete());
Uri Abramson
fuente
@VladL Obtengo un "IEnumerable <FileInfo> no contiene ForEach" si suelto el ToList (). Simplemente lo guardé.
James Love
3
Me gusta esto. Pero envolvería la eliminación en un try / catch
H20rider
new DirectoryInfo(dir).GetFiles()es más rápido que new FileInfo(f)para cada archivo.
Vojtěch Dohnal
29

Para aquellos a los que les gusta usar LINQ en exceso.

(from f in new DirectoryInfo("C:/Temp").GetFiles()
 where f.CreationTime < DateTime.Now.Subtract(TimeSpan.FromDays(90))
 select f
).ToList()
    .ForEach(f => f.Delete());
Samuel Neff
fuente
1
var filesToDelete = new DirectoryInfo (@ "C: \ Temp"). GetFiles (). Donde (x => x.LastAccessTime <DateTime.Now.AddMonths (-3)); // variación
Ta01
2
¡Woho! ¡Alguien más que yo piensa que usar LINQ en exceso es increíble! ;)
Filip Ekberg
¿Qué .ToList()agrega la llamada aparte de un segundo bucle a través de los archivos coincidentes?
Joel Mueller
2
@Joel Mueller. List<T>define un ForEachmétodo que se puede utilizar para aplicar un Action<T>a todos los elementos. Desafortunadamente, no existe tal método de extensión para IEnumerable<T>.
Samuel Neff
1
Buen punto. Escribí mi propio ForEachmétodo de IEnumerable<T>extensión hace tanto tiempo que a veces olvido que no está integrado.
Joel Mueller
14

Aquí hay un fragmento de cómo obtener la hora de creación de los archivos en el directorio y encontrar los que se crearon hace 3 meses (hace 90 días para ser exactos):

    DirectoryInfo source = new DirectoryInfo(sourceDirectoryPath);

    // Get info of each file into the directory
    foreach (FileInfo fi in source.GetFiles())
    {
        var creationTime = fi.CreationTime;

        if(creationTime < (DateTime.Now- new TimeSpan(90, 0, 0, 0)))
        {
            fi.Delete();
        }
    }
Pierre-Luc Champigny
fuente
No es necesario ToList(), DirectoryInfo.GetFiles()devuelve a FileInfo[].
Dynami Le Savard
4
Debe declarar una nueva variable fuera del foreach()ciclo para mantener el valor de (DateTime.Now- new TimeSpan(90, 0, 0, 0)). No hay razón para calcular eso repetidamente en el ciclo.
Chad
1

Básicamente, puede usar Directory.Getfiles (Path) para obtener una lista de todos los archivos. Después de eso, recorre la lista y llama a GetLastAccessTim () como sugirió Keith.

Ian Jacobs
fuente
1

Algo como eso

            foreach (FileInfo file in new DirectoryInfo("SomeFolder").GetFiles().Where(p => p.CreationTime < DateTime.Now.AddDays(-90)).ToArray())
                File.Delete(file.FullName);
Yiannis Leoussis
fuente
1

He probado este código y funciona muy bien, espero que esto responda

namespace EraseJunkFiles
{
    class Program
    {
        static void Main(string[] args)
        {
            DirectoryInfo yourRootDir = new DirectoryInfo(@"C:\yourdirectory\");
            foreach (FileInfo file in yourRootDir.GetFiles())
                if (file.LastWriteTime < DateTime.Now.AddDays(-90))
                    file.Delete();
        }
    }
}
Rosidin Bima
fuente
2
90 días <> 3 meses
Daniel
1

El enfoque más canónico cuando se desea eliminar archivos durante un período determinado es utilizar el LastWriteTime del archivo (la última vez que se modificó el archivo):

Directory.GetFiles(dirName)
         .Select(f => new FileInfo(f))
         .Where(f => f.LastWriteTime < DateTime.Now.AddMonths(-3))
         .ToList()
         .ForEach(f => f.Delete());

(Lo anterior se basa en la respuesta de Uri pero con LastWriteTime.)

Siempre que escuche a personas hablar sobre la eliminación de archivos con una antigüedad superior a un cierto período de tiempo (que es una actividad bastante común), hacerlo basándose en el LastModifiedTime del archivo es casi siempre lo que están buscando.

Alternativamente, para circunstancias muy inusuales, puede usar los siguientes, pero utilícelos con precaución ya que vienen con advertencias.

CreationTime
.Where(f => f.CreationTime < DateTime.Now.AddMonths(-3))

La hora en que se creó el archivo en la ubicación actual. Sin embargo, tenga cuidado si el archivo se copió, será la hora en que se copió y CreationTimeserá más reciente que el archivo LastWriteTime.

LastAccessTime
.Where(f => f.LastAccessTime < DateTime.Now.AddMonths(-3))

Si desea eliminar los archivos basándose en la última vez que se leyeron, puede usar esto, pero no hay garantía de que se actualizará, ya que se puede deshabilitar en NTFS. Verifique fsutil behavior query DisableLastAccesssi está encendido. Además, en NTFS, puede tardar hasta una hora en actualizar el LastAccessTime del archivo después de acceder a él.

Tolga
fuente
0

solo necesita FileInfo -> CreationTime

y que simplemente calcular la diferencia horaria.

en app.config puede guardar el valor TimeSpan de la antigüedad que debe tener el archivo para eliminarlo

también consulte el método DateTime Subtract .

buena suerte

nWorx
fuente
0
            system.IO;

             List<string> DeletePath = new List<string>();
            DirectoryInfo info = new DirectoryInfo(Server.MapPath("~\\TempVideos"));
            FileInfo[] files = info.GetFiles().OrderBy(p => p.CreationTime).ToArray();
            foreach (FileInfo file in files)
            {
                DateTime CreationTime = file.CreationTime;
                double days = (DateTime.Now - CreationTime).TotalDays;
                if (days > 7)
                {
                    string delFullPath = file.DirectoryName + "\\" + file.Name;
                    DeletePath.Add(delFullPath);
                }
            }
            foreach (var f in DeletePath)
            {
                if (File.Exists(F))
                {
                    File.Delete(F);
                }
            }

uso en la carga de la página o servicio web o cualquier otro uso.

Mi concepto es evrry 7 días tengo que eliminar el archivo de la carpeta sin usar DB

vishal
fuente
0
         //Store the number of days after which you want to delete the logs.
         int Days = 30;

          // Storing the path of the directory where the logs are stored.
           String DirPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6) + "\\Log(s)\\";

          //Fetching all the folders.
            String[] objSubDirectory = Directory.GetDirectories(DirPath);

            //For each folder fetching all the files and matching with date given 
            foreach (String subdir in objSubDirectory)     
            {
                //Getting the path of the folder                 
                String strpath = Path.GetFullPath(subdir);
                //Fetching all the files from the folder.
                String[] strFiles = Directory.GetFiles(strpath);
                foreach (string files in strFiles)
                {
                    //For each file checking the creation date with the current date.
                    FileInfo objFile = new FileInfo(files);
                    if (objFile.CreationTime <= DateTime.Now.AddDays(-Days))
                    {
                        //Delete the file.
                        objFile.Delete();
                    }
                }

                //If folder contains no file then delete the folder also.
                if (Directory.GetFiles(strpath).Length == 0)
                {
                    DirectoryInfo objSubDir = new DirectoryInfo(subdir);
                    //Delete the folder.
                    objSubDir.Delete();
                }

            }
Arihant Lodha
fuente
0

Por ejemplo: para ir a Mi proyecto de carpeta en la fuente, necesito subir dos carpetas. Hago este algoritmo a 2 días a la semana y a cuatro horas.

public static void LimpiarArchivosViejos()
    {
        DayOfWeek today = DateTime.Today.DayOfWeek;
        int hora = DateTime.Now.Hour;
        if(today == DayOfWeek.Monday || today == DayOfWeek.Tuesday && hora < 12 && hora > 8)
        {
            CleanPdfOlds();
            CleanExcelsOlds();
        }

    }
    private static void CleanPdfOlds(){
        string[] files = Directory.GetFiles("../../Users/Maxi/Source/Repos/13-12-2017_config_pdfListados/ApplicaAccWeb/Uploads/Reports");
        foreach (string file in files)
        {
            FileInfo fi = new FileInfo(file);
            if (fi.CreationTime < DateTime.Now.AddDays(-7))
                fi.Delete();
        }
    }
    private static void CleanExcelsOlds()
    {
        string[] files2 = Directory.GetFiles("../../Users/Maxi/Source/Repos/13-12-2017_config_pdfListados/ApplicaAccWeb/Uploads/Excels");
        foreach (string file in files2)
        {
            FileInfo fi = new FileInfo(file);
            if (fi.CreationTime < DateTime.Now.AddDays(-7))
                fi.Delete();
        }
    }
Maximiliano Cesán
fuente
0

Utilizo lo siguiente en una aplicación de consola, ejecutándose como un servicio, para obtener información del directorio del archivo App.Settings. El número de días para conservar los archivos también se puede configurar, multiplicado por -1 para su uso en el método AddDays () de DateTime.Now.

static void CleanBackupFiles()
        {
            string gstrUncFolder = ConfigurationManager.AppSettings["DropFolderUNC"] + "";
            int iDelAge = Convert.ToInt32(ConfigurationManager.AppSettings["NumDaysToKeepFiles"]) * -1;
            string backupdir = string.Concat(@"\", "Backup", @"\");

            string[] files = Directory.GetFiles(string.Concat(gstrUncFolder, backupdir));


            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                if (fi.CreationTime < DateTime.Now.AddDays(iDelAge))
                {
                    fi.Delete();
                }
            }

        }
n122vu
fuente
0

Un tipo de ejemplo de SSIS ... (si esto ayuda a alguien)

          public void Main()
          {
                 // TODO: Add your code here
        // Author: Allan F 10th May 2019

        //first part of process .. put any files of last Qtr (or older) in Archive area 
        //e.g. if today is 10May2019 then last quarter is 1Jan2019 to 31March2019 .. any files earlier than 31March2019 will be archived

        //string SourceFileFolder = "\\\\adlsaasf11\\users$\\aford05\\Downloads\\stage\\";
        string SourceFilesFolder = (string)Dts.Variables["SourceFilesFolder"].Value;
        string ArchiveFolder = (string)Dts.Variables["ArchiveFolder"].Value;
        string FilePattern = (string)Dts.Variables["FilePattern"].Value;
        string[] files = Directory.GetFiles(SourceFilesFolder, FilePattern);

        //DateTime date = new DateTime(2019, 2, 15);//commented out line .. just for testing the dates .. 

        DateTime date = DateTime.Now;
        int quarterNumber = (date.Month - 1) / 3 + 1;
        DateTime firstDayOfQuarter = new DateTime(date.Year, (quarterNumber - 1) * 3 + 1, 1);
        DateTime lastDayOfQuarter = firstDayOfQuarter.AddMonths(3).AddDays(-1);

        DateTime LastDayOfPriorQuarter = firstDayOfQuarter.AddDays(-1);
        int PrevQuarterNumber = (LastDayOfPriorQuarter.Month - 1) / 3 + 1;
        DateTime firstDayOfLastQuarter = new DateTime(LastDayOfPriorQuarter.Year, (PrevQuarterNumber - 1) * 3 + 1, 1);
        DateTime lastDayOfLastQuarter = firstDayOfLastQuarter.AddMonths(3).AddDays(-1);

        //MessageBox.Show("debug pt2: firstDayOfQuarter" + firstDayOfQuarter.ToString("dd/MM/yyyy"));
        //MessageBox.Show("debug pt2: firstDayOfLastQuarter" + firstDayOfLastQuarter.ToString("dd/MM/yyyy"));


        foreach (string file in files)
        {
            FileInfo fi = new FileInfo(file);

            //MessageBox.Show("debug pt2:" + fi.Name + " " + fi.CreationTime.ToString("dd/MM/yyyy HH:mm") + " " + fi.LastAccessTime.ToString("dd/MM/yyyy HH:mm") + " " + fi.LastWriteTime.ToString("dd/MM/yyyy HH:mm"));
            if (fi.LastWriteTime < firstDayOfQuarter)
            {

                try
                {

                    FileInfo fi2 = new FileInfo(ArchiveFolder);

                    //Ensure that the target does not exist.
                    //fi2.Delete();

                    //Copy the file.
                    fi.CopyTo(ArchiveFolder + fi.Name);
                    //Console.WriteLine("{0} was copied to {1}.", path, ArchiveFolder);

                    //Delete the old location file.
                    fi.Delete();
                    //Console.WriteLine("{0} was successfully deleted.", ArchiveFolder);

                }
                catch (Exception e)
                {
                    //do nothing
                    //Console.WriteLine("The process failed: {0}", e.ToString());
                }
            }
        }

        //second part of process .. delete any files in Archive area dated earlier than last qtr ..
        //e.g. if today is 10May2019 then last quarter is 1Jan2019 to 31March2019 .. any files earlier than 1Jan2019 will be deleted

        string[] archivefiles = Directory.GetFiles(ArchiveFolder, FilePattern);
        foreach (string archivefile in archivefiles)
        {
            FileInfo fi = new FileInfo(archivefile);
            if (fi.LastWriteTime < firstDayOfLastQuarter )
            {
                try
                {
                    fi.Delete();
                }
                catch (Exception e)
                {
                    //do nothing
                }
            }
        }


                 Dts.TaskResult = (int)ScriptResults.Success;
          }
Allan F
fuente
0

dado que las soluciones con new FileInfo(filePath)no se pueden probar fácilmente, sugiero usar Wrappers para clases como Directory, Filey Pathasí:

public interface IDirectory
{
    string[] GetFiles(string path);
}

public sealed class DirectoryWrapper : IDirectory
{
    public string[] GetFiles(string path) => Directory.GetFiles(path);
}

public interface IFile
{
    void Delete(string path);
    DateTime GetLastAccessTime(string path);
}

public sealed class FileWrapper : IFile
{
    public void Delete(string path) => File.Delete(path);
    public DateTime GetLastAccessTimeUtc(string path) => File.GetLastAccessTimeUtc(path);
}

Luego usa algo como esto:

public sealed class FooBar
{
    public FooBar(IFile file, IDirectory directory)
    {
        File = file;
        Directory = directory;
    }

    private IFile File { get; }
    private IDirectory Directory { get; }

    public void DeleteFilesBeforeTimestamp(string path, DateTime timestamp)
    {
        if(!Directory.Exists(path))
            throw new DirectoryNotFoundException($"The path {path} was not found.");

        var files = Directory
            .GetFiles(path)
            .Select(p => new
            {
                Path = p,
                // or File.GetLastWriteTime() or File.GetCreationTime() as needed
                LastAccessTimeUtc = File.GetLastAccessTimeUtc(p) 
            })
            .Where(p => p.LastAccessTimeUtc < timestamp);

        foreach(var file in files)
        {
            File.Delete(file.Path);
        }
    }
}
MovGP0
fuente
0

Simplemente cree una pequeña función de eliminación que pueda ayudarlo a lograr esta tarea. He probado este código y funciona perfectamente.

Esta función elimina archivos de más de 90 días , así como un archivo con extensión .zip para ser eliminado de una carpeta.

Private Sub DeleteZip()

    Dim eachFileInMydirectory As New DirectoryInfo("D:\Test\")
    Dim fileName As IO.FileInfo

    Try
        For Each fileName In eachFileInMydirectory.GetFiles
            If fileName.Extension.Equals("*.zip") AndAlso (Now - fileName.CreationTime).Days > 90 Then
                fileName.Delete()
            End If
        Next

    Catch ex As Exception
        WriteToLogFile("No Files older than 90 days exists be deleted " & ex.Message)
    End Try
End Sub
Rachit Rastogi
fuente