Usuń pliki starsze niż 3 miesiące z katalogu przy użyciu platformy .NET

118

Chciałbym wiedzieć (używając C #), jak mogę usunąć pliki w określonym katalogu starszym niż 3 miesiące, ale myślę, że okres dat mógłby być elastyczny.

Dla jasności: szukam plików starszych niż 90 dni, innymi słowy, pliki utworzone mniej niż 90 dni temu powinny zostać zachowane, wszystkie inne usunięte.

J L.
źródło
Jeśli istnieje duża liczba plików, najlepiej jest użyć EnumerateFiles i EnumerateDirectories zamiast GetFiles i GetDirectories, ponieważ bezpośrednio uruchamiają wyliczenie zamiast gromadzenia listy. Będziesz jednak musiał użyć pętli foreach.
Larry

Odpowiedzi:

258

Coś takiego nie wystarczy.

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
źródło
Dzięki, zauważyłem, że używasz lastAccessTime, czy to jest czas tworzenia?
JL.
10
nie, jak mówi propertyNames: LastAccessTime- jeśli chcesz, powinieneś wybrać opcję property CreationTime!
Andreas Niedermair
4
Tak, z której właściwości korzystasz, zależy wyłącznie od Ciebie. Możesz także użyć LastWriteTime, jeśli chcesz.
Steve Danner
3
+1 za pomoc. Zamiast tworzyć nową instancję FileInfo, możesz użyć File.GetCreationTime lub File.GetLastAccessTime. Powinien być niewielki wzrost wydajności.
Mario The Spoon
5
Sądzę, że GetFiles i Delete nigdy nie zawodzą w Twoim środowisku? Zwracam na to uwagę, ponieważ wydaje się, że jest to wysoce referencyjna odpowiedź.
Andrew Hagner
93

Oto 1-liniowa lambda:

Directory.GetFiles(dirName)
         .Select(f => new FileInfo(f))
         .Where(f => f.LastAccessTime < DateTime.Now.AddMonths(-3))
         .ToList()
         .ForEach(f => f.Delete());
Uri Abramson
źródło
@VladL Otrzymuję „IEnumerable <FileInfo> nie zawiera ForEach”, jeśli porzucę ToList (). Po prostu zatrzymałem to.
James Love,
3
Lubię to. Ale
owinąłbym
new DirectoryInfo(dir).GetFiles()jest szybszy niż w new FileInfo(f)przypadku każdego pojedynczego pliku.
Vojtěch Dohnal
29

Dla tych, którzy lubią nadmiernie używać 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
źródło
1
var filesToDelete = new DirectoryInfo (@ "C: \ Temp"). GetFiles (). Where (x => x.LastAccessTime <DateTime.Now.AddMonths (-3)); // odmiana
Ta01
2
Woho! Ktoś inny niż ja uważa, że ​​nadmierne używanie LINQ jest niesamowite! ;)
Filip Ekberg
Co dodaje .ToList()wywołanie oprócz drugiej pętli przez dopasowane pliki?
Joel Mueller
2
@Joel Mueller. List<T>definiuje ForEachmetodę, którą można zastosować Action<T>do wszystkich elementów. Niestety nie ma takiej metody rozszerzenia dla IEnumerable<T>.
Samuel Neff
1
Słuszna uwaga. Napisałem swoją własną ForEachmetodę rozszerzenia IEnumerable<T>tak dawno temu, czasami zapominam, że nie jest ona wbudowana.
Joel Mueller,
14

Oto fragment pokazujący, jak uzyskać czas utworzenia plików w katalogu i znaleźć te, które zostały utworzone 3 miesiące temu (dokładnie 90 dni temu):

    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
źródło
Nie ma potrzeby ToList(), DirectoryInfo.GetFiles()zwraca a FileInfo[].
Dynami Le Savard
4
Powinieneś zadeklarować nową zmienną poza foreach()pętlą, która będzie przechowywać wartość (DateTime.Now- new TimeSpan(90, 0, 0, 0)). Nie ma powodu, aby wielokrotnie to obliczać w pętli.
Czad
1

Zasadniczo możesz użyć Directory.Getfiles (Path), aby uzyskać listę wszystkich plików. Następnie przeglądasz listę i wywołujesz GetLastAccessTim () zgodnie z sugestią Keitha.

Ian Jacobs
źródło
1

Coś w tym stylu

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

Wypróbowałem ten kod i działa bardzo dobrze, mam nadzieję, że odpowiedź

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
źródło
2
90 dni <> 3 miesiące
Daniel
1

Najbardziej kanonicznym podejściem, gdy chcesz usunąć pliki przez określony czas, jest użycie LastWriteTime pliku (ostatnia modyfikacja pliku):

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

(Powyższe oparte na odpowiedzi Uri, ale z LastWriteTime.)

Ilekroć słyszysz, jak ludzie mówią o usuwaniu plików starszych niż określone ramy czasowe (co jest dość powszechną czynnością), robienie tego na podstawie LastModifiedTime pliku jest prawie zawsze tym, czego szukają.

Alternatywnie, w bardzo nietypowych okolicznościach możesz skorzystać z poniższych, ale używaj ich ostrożnie, ponieważ zawierają zastrzeżenia.

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

Czas utworzenia pliku w bieżącej lokalizacji. Uważaj jednak, jeśli plik został skopiowany, będzie to czas, w którym został skopiowany i CreationTimebędzie nowszy niż plik LastWriteTime.

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

Jeśli chcesz usunąć pliki na podstawie ostatniego odczytu, możesz tego użyć, ale nie ma gwarancji, że zostanie zaktualizowany, ponieważ można go wyłączyć w systemie plików NTFS. Sprawdź, fsutil behavior query DisableLastAccessczy jest włączony. Również w systemie NTFS może minąć nawet godzina, zanim plik LastAccessTime zostanie zaktualizowany po uzyskaniu do niego dostępu.

Tolga
źródło
0

potrzebujesz tylko FileInfo -> CreationTime

a nie tylko obliczać różnicę czasu.

w app.config można zapisać TimeSpan pliku wartość określającą, jak stary plik musi być usunięty

sprawdź także Odejmowanie daty i czasu metodę .

powodzenia

nWorx
źródło
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);
                }
            }

używać podczas ładowania strony lub usługi sieciowej lub w jakimkolwiek innym celu.

Moja koncepcja to evrry 7 dni muszę usunąć plik folderu bez korzystania z DB

Vishal
źródło
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
źródło
0

Na przykład: Aby przejść do mojego projektu folderu na źródle, potrzebuję maksymalnie dwóch folderów. Robię ten algorim na 2 dni w tygodniu i na cztery godziny

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
źródło
0

Używam następujących elementów w aplikacji konsoli, działającej jako usługa, aby uzyskać informacje o katalogu z pliku App.Settings. Liczba dni przechowywania plików jest również konfigurowalna, pomnożona przez -1 do użycia w metodzie AddDays () obiektu 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
źródło
0

Przykład typu SSIS ... (jeśli to komuś pomoże)

          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
źródło
0

ponieważ roztwory new FileInfo(filePath)nie są łatwo sprawdzalne, proponuję używać opakowań dla klas, takich jak Directory, Filei Pathtak:

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

Następnie użyj czegoś takiego:

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
źródło
0

Po prostu stwórz małą funkcję usuwania, która pomoże ci wykonać to zadanie, przetestowałem ten kod i działa doskonale.

Ta funkcja usuwa pliki starsze niż 90 dni, a także plik z rozszerzeniem .zip, który ma zostać usunięty z folderu.

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
źródło