151

I would like to know (using C#) how I can delete files in a certain directory older than 3 months, but I guess the date period could be flexible.

Just to be clear: I am looking for files that are older than 90 days, in other words files created less than 90 days ago should be kept, all others deleted.

bluish
  • 26,356
  • 27
  • 122
  • 180
JL.
  • 78,954
  • 126
  • 311
  • 459
  • 1
    If there is a important amount of files, the best is to use EnumerateFiles and EnumerateDirectories instead of GetFiles and GetDirectories, because they directly run the enumeration instead of gathering a list. However, you will have to use a foreach loop. – Larry Jun 04 '15 at 20:24

18 Answers18

316

Something like this outta do it.

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
  • 21,818
  • 7
  • 41
  • 51
  • 1
    Thanks, I noticed you're using lastAccessTime, is this the creation time? – JL. Feb 08 '10 at 14:59
  • 17
    no, as propertyNames says: `LastAccessTime` - you should go for property `CreationTime` if you'd like to! –  Feb 08 '10 at 15:01
  • 4
    Yeah, which property you use is entirely up to you. You could also use LastWriteTime if you wanted. – Steve Danner Feb 08 '10 at 15:05
  • Sorry to ask, but are you 100% sure about the comparison operator being less than? does this mean that the first date should be less than the 2nd date? – JL. Feb 08 '10 at 15:09
  • No need to apologize, that is how you learn! Yes, I'm positive. It means the last access time on the file is less than the date 3 months ago from this moment. – Steve Danner Feb 08 '10 at 15:11
  • Ok thanks Steve, you got here first with a great answer, thanks again! – JL. Feb 08 '10 at 15:12
  • 4
    +1 for helping me out. Instead of creating a new FileInfo instance you could use File.GetCreationTime or File.GetLastAccessTime. Should be a minor performance improvement. – Mario The Spoon Mar 20 '11 at 10:47
  • 5
    I guess GetFiles and Delete never fail in your environment? Just pointing that out since this seems to be a highly referenced answer. – Andrew Hagner Jun 28 '13 at 14:04
  • LastWriteTime is the datetime visible in standard file explorer .. I'm going with a test against this attribute. Yep - I would put in a try catch .. – Allan F May 10 '19 at 03:16
  • 1
    Why do evaluate each loop DateTime.Now.AddMonths(-3) ? – Armando Contestabile Apr 21 '22 at 11:01
106

Here's a 1-liner lambda:

Directory.GetFiles(dirName)
         .Select(f => new FileInfo(f))
         .Where(f => f.LastAccessTime < DateTime.Now.AddMonths(-3))
         .ToList()
         .ForEach(f => f.Delete());
Uri Abramson
  • 6,005
  • 6
  • 40
  • 62
29

For those that like to over-use LINQ.

(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
  • 73,278
  • 17
  • 138
  • 182
  • 1
    var filesToDelete = new DirectoryInfo(@"C:\Temp").GetFiles().Where(x=>x.LastAccessTime < DateTime.Now.AddMonths(-3)); //variation – Ta01 Feb 08 '10 at 15:23
  • 2
    Woho! Someone else than me thinks over-using LINQ is awesome! ;) – Filip Ekberg Feb 08 '10 at 15:57
  • What does the `.ToList()` call add other than a second loop through the matched files? – Joel Mueller Feb 08 '10 at 21:23
  • 2
    @Joel Mueller. `List` defines a `ForEach` method which can be used to apply an `Action` to all elements. Unfortunately there is no such extension method for `IEnumerable`. – Samuel Neff Feb 08 '10 at 22:04
  • 1
    Good point. I wrote my own `ForEach` extension method for `IEnumerable` so long ago, I sometimes forget it isn't built in. – Joel Mueller Feb 08 '10 at 22:33
  • For those with no shame: `new DirectoryInfo(@"C:\Temp").GetFiles("*.log").AsParallel().Where(f => f.LastWriteTime < DateTime.Now - TimeSpan.FromDays(90)).ForAll(f => f.Delete());` – abrkn Sep 18 '12 at 09:01
  • Since the tasks are all reading/writing from the same disk I'm not sure `AsParallel` is really appropriate here. It'd be good to test to be sure. – Samuel Neff Sep 18 '12 at 09:04
  • How would you handle a failed call to Delete via this Linq version? – Andrew Hagner Jun 28 '13 at 14:06
  • @AndrewHagner, I would add a new utility method like `DeleteSafe()` and include error handling in that to never throw an error even if delete fails. – Samuel Neff Oct 11 '13 at 23:35
14

Here's a snippet of how to get the creation time of files in the directory and find those which have been created 3 months ago (90 days ago to be exact):

    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();
        }
    }
  • No need for `ToList()`, `DirectoryInfo.GetFiles()` returns a `FileInfo[]`. – Dynami Le Savard Feb 09 '10 at 01:52
  • 6
    You should declare a new variable outside the `foreach()` loop to hold the value of `(DateTime.Now- new TimeSpan(90, 0, 0, 0))`. There is no reason to calculate that repeatedly in the loop. – Chad May 11 '17 at 18:29
7

The most canonical approach when wanting to delete files over a certain duration is by using the file's LastWriteTime (Last time the file was modified):

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

(The above based on Uri's answer but with LastWriteTime.)

Whenever you hear people talking about deleting files older than a certain time frame (which is a pretty common activity), doing it based on the file's LastModifiedTime is almost always what they are looking for.

Alternatively, for very unusual circumstances you could use the below, but use these with caution as they come with caveats.

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

The time the file was created in the current location. However, be careful if the file was copied, it will be the time it was copied and CreationTime will be newer than the file's LastWriteTime.

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

If you want to delete the files based on the last time they were read you could use this but, there is no guarantee it will be updated as it can be disabled in NTFS. Check fsutil behavior query DisableLastAccess to see if it is on. Also under NTFS it may take up to an hour for the file's LastAccessTime to update after it was accessed.

Tolga
  • 2,643
  • 1
  • 27
  • 18
3

The GetLastAccessTime property on the System.IO.File class should help.

Keith Bloom
  • 2,391
  • 3
  • 18
  • 30
1

Basically you can use Directory.Getfiles(Path) to get a list of all the files. After that you loop through the list and call GetLastAccessTim() as Keith suggested.

Ian Jacobs
  • 5,456
  • 1
  • 23
  • 38
1

Something like that

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

i have try this code and it works very well, hope this answered

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
  • 227
  • 3
  • 5
0

you just need FileInfo -> CreationTime

and than just calculate the time difference.

in the app.config you can save the TimeSpan value of how old the file must be to be deleted

also check out the DateTime Subtract method.

good luck

nWorx
  • 2,145
  • 16
  • 37
0

Alternatively, you can use the File.GetCreationTime Method if you need to delete files based on creation dates.

jinsungy
  • 10,717
  • 24
  • 71
  • 79
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);
                }
            }

use in page load or webservice or any other use.

My concept is evrry 7 day i have to delete folder file without using DB

vishal
  • 1
  • 1
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();
                }

            }
0

Just create a small delete function which can help you to achieve this task, I have tested this code and it runs perfectly well.

This function deletes files older than 90 days as well as a file with extension .zip to be deleted from a folder.

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
0

For example: To go My folder project on source, i need to up two folder. I make this algorim to 2 days week and into four hour

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();
        }
    }
0

I use the following in a console app, running as a service, to get directory info from the App.Settings file. Number of days to keep the files is also configurable, multiplied by -1 for use in the AddDays() method of 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
  • 31
  • 6
0

An SSIS type of example .. (if this helps anyone)

          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
  • 2,110
  • 1
  • 24
  • 29
0

since the solutions with new FileInfo(filePath) are not easily testable, I suggest to use Wrappers for classes like Directory, File and Path like this:

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);
}

Then use something like this:

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
  • 7,267
  • 3
  • 49
  • 42