Exclua arquivos com mais de 3 meses em um diretório usando .NET

117

Gostaria de saber (usando C #) como posso excluir arquivos em um determinado diretório com mais de 3 meses, mas acho que o período de datas pode ser flexível.

Só para deixar claro: procuro arquivos com mais de 90 dias, ou seja, os arquivos criados há menos de 90 dias devem ser mantidos, todos os outros excluídos.

JL.
fonte
Se houver uma quantidade importante de arquivos, o melhor é usar EnumerateFiles e EnumerateDirectories em vez de GetFiles e GetDirectories, porque eles executam diretamente a enumeração em vez de reunir uma lista. No entanto, você terá que usar um loop foreach.
Larry

Respostas:

257

Algo assim não dá certo.

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
fonte
Obrigado, percebi que você está usando lastAccessTime. É o horário de criação?
JL.
10
não, como diz propertyNames: LastAccessTime- você deve ir para a propriedade CreationTimese quiser!
Andreas Niedermair
4
Sim, a propriedade que você usa depende inteiramente de você. Você também pode usar LastWriteTime se quiser.
Steve Danner
3
1 por me ajudar. Em vez de criar uma nova instância de FileInfo, você pode usar File.GetCreationTime ou File.GetLastAccessTime. Deve ser uma pequena melhoria de desempenho.
Mario The Spoon
5
Eu acho que GetFiles e Delete nunca falham em seu ambiente? Apenas apontando isso, uma vez que esta parece ser uma resposta altamente referenciada.
Andrew Hagner
93

Aqui está um lambda de 1 linha:

Directory.GetFiles(dirName)
         .Select(f => new FileInfo(f))
         .Where(f => f.LastAccessTime < DateTime.Now.AddMonths(-3))
         .ToList()
         .ForEach(f => f.Delete());
Uri Abramson
fonte
@VladL Recebo um "IEnumerable <FileInfo> não contém ForEach" se descartar o ToList (). Eu apenas guardei.
James Love
3
Eu gosto disso. Mas eu envolveria a exclusão em um try / catch
H20rider
new DirectoryInfo(dir).GetFiles()é mais rápido do que new FileInfo(f)para cada arquivo.
Vojtěch Dohnal
29

Para aqueles que gostam de usar o LINQ em excesso.

(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
fonte
1
var filesToDelete = new DirectoryInfo (@ "C: \ Temp"). GetFiles (). Onde (x => x.LastAccessTime <DateTime.Now.AddMonths (-3)); // variação
Ta01 de
2
Uau! Alguém além de mim acha que usar o LINQ em excesso é incrível! ;)
Filip Ekberg
O que a .ToList()chamada adiciona além de um segundo loop pelos arquivos correspondentes?
Joel Mueller
2
@Joel Mueller. List<T>define um ForEachmétodo que pode ser usado para aplicar um Action<T>a todos os elementos. Infelizmente, não existe tal método de extensão para IEnumerable<T>.
Samuel Neff
1
Bom ponto. Escrevi meu próprio ForEachmétodo de IEnumerable<T>extensão há muito tempo, às vezes esqueço que ele não está integrado.
Joel Mueller
14

Aqui está um snippet de como obter a hora de criação de arquivos no diretório e encontrar aqueles que foram criados há 3 meses (90 dias atrás, para ser exato):

    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
fonte
Não há necessidade de ToList(), DirectoryInfo.GetFiles()retorna a FileInfo[].
Dynami Le Savard
4
Você deve declarar uma nova variável fora do foreach()loop para conter o valor (DateTime.Now- new TimeSpan(90, 0, 0, 0)). Não há razão para calcular isso repetidamente no loop.
Chade
1

Basicamente, você pode usar Directory.Getfiles (Path) para obter uma lista de todos os arquivos. Depois disso, você percorre a lista e chama GetLastAccessTim () conforme sugerido por Keith.

Ian Jacobs
fonte
1

Algo parecido

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

Tentei este código e funciona muito bem, espero que esta resposta

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
fonte
2
90 dias <> 3 meses
Daniel
1

A abordagem mais canônica quando se deseja excluir arquivos em um determinado período é usar o LastWriteTime do arquivo (última vez que o arquivo foi modificado):

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

(O texto acima é baseado na resposta de Uri, mas com LastWriteTime.)

Sempre que você ouvir pessoas falando sobre excluir arquivos mais antigos que um determinado período de tempo (o que é uma atividade bastante comum), fazê-lo com base no LastModifiedTime do arquivo é quase sempre o que eles estão procurando.

Como alternativa, em circunstâncias muito incomuns, você pode usar o abaixo, mas use-os com cuidado, pois eles vêm com advertências.

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

A hora em que o arquivo foi criado no local atual. Porém, tome cuidado se o arquivo foi copiado, será a hora em que foi copiado e CreationTimeserá mais recente que o do arquivo LastWriteTime.

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

Se quiser excluir os arquivos com base na última vez em que foram lidos, você pode usar isso, mas não há garantia de que será atualizado, pois pode ser desativado em NTFS. Verifique fsutil behavior query DisableLastAccessse está ligado. Além disso, em NTFS, pode levar até uma hora para que o LastAccessTime do arquivo seja atualizado após ter sido acessado.

Tolga
fonte
0

você só precisa de FileInfo -> CreationTime

e do que apenas calcular a diferença de tempo.

no app.config você pode salvar o valor de TimeSpan de quantos anos o arquivo deve ter para ser excluído

também verifique o método DateTime Subtract .

boa sorte

nWorx
fonte
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 no carregamento da página ou serviço da web ou qualquer outro uso.

Meu conceito é evrry 7 dias eu tenho que deletar o arquivo da pasta sem usar DB

vishal
fonte
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
fonte
0

Por exemplo: Para ir para Meu projeto de pasta na origem, preciso de até duas pastas. Eu faço este algoritmo para 2 dias por semana e em quatro 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
fonte
0

Eu uso o seguinte em um aplicativo de console, rodando como um serviço, para obter informações de diretório do arquivo App.Settings. O número de dias para manter os arquivos também é configurável, multiplicado por -1 para uso no 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
fonte
0

Um tipo de exemplo SSIS .. (se isso ajudar alguém)

          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
fonte
0

uma vez que as soluções com new FileInfo(filePath)não são facilmente testáveis, sugiro usar Wrappers para classes como Directory, Filee Pathassim:

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

Em seguida, use algo assim:

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
fonte
0

Basta criar uma pequena função de exclusão que pode ajudá-lo a realizar essa tarefa, eu testei esse código e ele funciona perfeitamente bem.

Esta função exclui arquivos com mais de 90 dias , bem como um arquivo com extensão .zip a ser excluído de uma pasta.

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
fonte