none
Getting a list of all files created/modified in last x hours RRS feed

  • Question

  • Hi

    I am trying to find a way to get a list of all files created/modified in the last x hours.

    This is something I can do easily from Powershell using

    Get-ChildItem -Recurse | where-object { $_.lastwritetime -gt (get-date).addHours(-24)}

    But I am trying to do it in VB and have tried using things such as Directory.GetFiles and Directory.EnumerateFiles e.g.

     Dim today As DateTime = DateTime.Now.Date
            Dim todaysFiles() As FileInfo = (New DirectoryInfo("c:\")).EnumerateFiles("*.*", searchOption.AllDirectories).Select(Function(x)
                                                                                                          x.Refresh()
                                                                                                          Return x
                                                                                                      End Function).Where(Function(x) x.CreationTime.Date = today OrElse x.LastWriteTime = today).ToArray()
    

    or

    Dim directory = New DirectoryInfo("C:\")
            
    Dim filesLst = directory.GetFiles("*.*", searchOption.AllDirectories).AsEnumerable().Where(Function(file) File.CreationTime.Date = DateTime.Now.Date).ToArray()

    But these both through errors (as I would expect) when hitting folders such as System Volume Information or C:\$Recycle.Bin

    Any ideas on how I can do what I need and just skip anything it doesn't have permission to access?  

    For info the app is running with admin rights


    Darren Rose

    Friday, August 23, 2019 5:30 PM

Answers

  • Hi

    Bit late to party, but I had almost finished before I had to leave it - now finished so here it is.

    Full text example project. As fast as I can get it (doubtless there are fater). Uses a BGW to jeep UI responsive.

    Not as compact as others, but does the job - gets a list of Modified files in Path during last XXX hours.(as it happens, also gets the list of locations failed due to UnAuthorized access etc)

    26 seconds to process almost 300000 files is not too bad though.

    ' BGW MODIFIED FILES LAST XXX HRS
    Option Strict On
    Option Explicit On
    
    Imports System.ComponentModel
    Imports System.IO
    
    Public Class Form1
      Dim Ignore As New List(Of String)
      Dim Failed As New List(Of String)
      Dim FileCount As Integer = 0
      Dim sw As New Stopwatch
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Shown
        Location = New Point(100, 100)
        Size = New Size(700, 400)
        MinimumSize = New Size(600, 200)
    
        ListBox2.SendToBack()
        ListBox2.Location = ListBox1.Location
        ListBox2.Size = ListBox1.Size
    
        ' create an Ignore extention list
        Ignore.AddRange({".wer", ".cache"})
    
      End Sub
      Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        GetFilesCreated(TextBox1.Text)
      End Sub
      Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    
        Label6.Text = FileCount.ToString
        Label7.Text = Failed.Count.ToString
        Dim ms As TimeSpan = sw.Elapsed
        Label8.Text = ms.ToString("h\h\ m\m\ s\s\ fff\m\s")
        sw.Reset()
        Label12.Text = ListBox1.Items.Count.ToString
        Label10.Text = "Ready ......."
        Button2.Text = "GO"
      End Sub
      Sub GetFilesCreated(initialfolder As String)
    
        If Not Directory.Exists(initialfolder) Then Exit Sub
    
        Dim lastHours As Integer
        Integer.TryParse(TextBox2.Text, lastHours)
        If lastHours < 1 Then Exit Sub
    
        Dim di As DirectoryInfo = New DirectoryInfo(initialfolder)
    
        Try
          For Each fi As FileInfo In di.GetFiles()
            If BackgroundWorker1.CancellationPending Then Exit Sub
            FileCount += 1
            If Not Ignore.Contains(fi.Extension) AndAlso fi.LastWriteTime >= Now.AddHours(-lastHours) Then
              Invoke(Sub() ListBox1.Items.Add(fi.FullName))
            End If
          Next
          Dim di2 As List(Of DirectoryInfo) = di.GetDirectories().ToList
          If di2.Count > 0 Then
            For Each s As DirectoryInfo In di2
              initialfolder = s.FullName
              GetFilesCreated(initialfolder)
            Next
          End If
        Catch ex1 As UnauthorizedAccessException
          Failed.Add(di.FullName)
          Invoke(Sub() ListBox2.Items.Add(di.FullName))
        End Try
      End Sub
      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim fb As New FolderBrowserDialog
        fb.Description = "Select Folder to work on"
        If Directory.Exists(TextBox1.Text) Then
          fb.SelectedPath = TextBox1.Text
        Else
          fb.SelectedPath = My.Computer.FileSystem.SpecialDirectories.MyDocuments
        End If
        If fb.ShowDialog = DialogResult.OK Then
          TextBox1.Text = fb.SelectedPath
        End If
      End Sub
      Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Select Case Button2.Text
          Case "GO"
            FileCount = 0
            Failed.Clear()
    
            Label6.Text = "0"
            Label7.Text = "0"
            Label8.Text = "0"
            ListBox1.Items.Clear()
            Label12.Text = "0"
            Label10.Text = "Working ....."
            Button2.Text = "STOP"
            sw.Start()
            BackgroundWorker1.RunWorkerAsync()
          Case Else
            BackgroundWorker1.CancelAsync()
        End Select
      End Sub
      Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Select Case Button3.Text
          Case "SHOW FAILED"
            ListBox2.BringToFront()
            Button3.Text = "SHOW RESULTS"
            Label9.Text = "Failed List"
          Case Else
            ListBox2.SendToBack()
            Button3.Text = "SHOW FAILED"
            Label9.Text = "Results List"
        End Select
      End Sub
    End Class


    Regards Les, Livingston, Scotland


    • Edited by leshay Saturday, August 24, 2019 2:44 PM
    • Marked as answer by wingers Saturday, August 24, 2019 10:24 PM
    Saturday, August 24, 2019 2:43 PM

All replies

  • To start with here are two methods

        Private Function GetFilesByDate(TheDir As IO.DirectoryInfo,
                                        GTdate As DateTime) As List(Of IO.FileInfo)
    
            Dim rv As New List(Of IO.FileInfo)
            Try
                rv.AddRange(From f In TheDir.EnumerateFiles("*.*", IO.SearchOption.TopDirectoryOnly)
                            Where f.CreationTime >= GTdate
                            Select f)
    
            Catch unaa As UnauthorizedAccessException
    
            Catch ex As Exception
                Stop
            End Try
            Return rv
        End Function
    
        Private Iterator Function IterateDirs(TheDir As IO.DirectoryInfo) As IEnumerable(Of IO.DirectoryInfo)
            Dim dirs As IEnumerable(Of IO.DirectoryInfo)
            dirs = TheDir.EnumerateDirectories("*.*",
                                               IO.SearchOption.TopDirectoryOnly)
            For Each d As IO.DirectoryInfo In dirs
                Try
                    Yield d
                    For Each sd As IO.DirectoryInfo In IterateDirs(d)
                        Yield sd
                    Next
                Catch unaa As UnauthorizedAccessException
    
                Catch ex As Exception
                    Stop
                End Try
            Next
        End Function
    

    To see them in use

            Dim path As String
            path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
            Dim di As New IO.DirectoryInfo(path)
            Dim todaysFiles As New List(Of IO.FileInfo)
            For Each d As IO.DirectoryInfo In IterateDirs(di)
                todaysFiles.AddRange(GetFilesByDate(d, DateTime.Now))
            Next
    


    Search Documentation

    SerialPort Info

    Multics - An OS ahead of its time.

     "Those who use Application.DoEvents have no idea what it does

        and those who know what it does never use it."    former MSDN User JohnWein

    Friday, August 23, 2019 6:25 PM
  • Hello Darren,

    Unfortunately there is no way to catch unauthorize exceptions as you are performing with the current code. Best suggestion is to use a for-next or for-each e.g.

    http://www.vbforums.com/showthread.php?638338-How-to-handle-Unauthorized-Access-Exception-when-getting-files


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, August 23, 2019 6:29 PM
    Moderator
  • Thank you both for your replies, much appreciated

    I will give that code a go and see how I get on :)


    Darren Rose

    Friday, August 23, 2019 6:53 PM
  • @dbasnett

    Hi, tried your code - had to change "TopDirectoryOnly" to "AllDirectories" as wanted to do a whole drive rather than just one folder level.

    It works for drives with not too many files / folders on, but if I try it on say my C: drive then Visual Studio doesn't like it and breaks out with an error I hadn't seen before:-

    "Managed Debugging Assistant 'ContextSwitchDeadlock' : 'The CLR has been unable to transition from COM context 0x12ca778 to COM context 0x12ca6c0 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.'"


    Darren Rose

    Friday, August 23, 2019 9:15 PM
  • Hi

    Bit late to party, but I had almost finished before I had to leave it - now finished so here it is.

    Full text example project. As fast as I can get it (doubtless there are fater). Uses a BGW to jeep UI responsive.

    Not as compact as others, but does the job - gets a list of Modified files in Path during last XXX hours.(as it happens, also gets the list of locations failed due to UnAuthorized access etc)

    26 seconds to process almost 300000 files is not too bad though.

    ' BGW MODIFIED FILES LAST XXX HRS
    Option Strict On
    Option Explicit On
    
    Imports System.ComponentModel
    Imports System.IO
    
    Public Class Form1
      Dim Ignore As New List(Of String)
      Dim Failed As New List(Of String)
      Dim FileCount As Integer = 0
      Dim sw As New Stopwatch
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Shown
        Location = New Point(100, 100)
        Size = New Size(700, 400)
        MinimumSize = New Size(600, 200)
    
        ListBox2.SendToBack()
        ListBox2.Location = ListBox1.Location
        ListBox2.Size = ListBox1.Size
    
        ' create an Ignore extention list
        Ignore.AddRange({".wer", ".cache"})
    
      End Sub
      Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        GetFilesCreated(TextBox1.Text)
      End Sub
      Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    
        Label6.Text = FileCount.ToString
        Label7.Text = Failed.Count.ToString
        Dim ms As TimeSpan = sw.Elapsed
        Label8.Text = ms.ToString("h\h\ m\m\ s\s\ fff\m\s")
        sw.Reset()
        Label12.Text = ListBox1.Items.Count.ToString
        Label10.Text = "Ready ......."
        Button2.Text = "GO"
      End Sub
      Sub GetFilesCreated(initialfolder As String)
    
        If Not Directory.Exists(initialfolder) Then Exit Sub
    
        Dim lastHours As Integer
        Integer.TryParse(TextBox2.Text, lastHours)
        If lastHours < 1 Then Exit Sub
    
        Dim di As DirectoryInfo = New DirectoryInfo(initialfolder)
    
        Try
          For Each fi As FileInfo In di.GetFiles()
            If BackgroundWorker1.CancellationPending Then Exit Sub
            FileCount += 1
            If Not Ignore.Contains(fi.Extension) AndAlso fi.LastWriteTime >= Now.AddHours(-lastHours) Then
              Invoke(Sub() ListBox1.Items.Add(fi.FullName))
            End If
          Next
          Dim di2 As List(Of DirectoryInfo) = di.GetDirectories().ToList
          If di2.Count > 0 Then
            For Each s As DirectoryInfo In di2
              initialfolder = s.FullName
              GetFilesCreated(initialfolder)
            Next
          End If
        Catch ex1 As UnauthorizedAccessException
          Failed.Add(di.FullName)
          Invoke(Sub() ListBox2.Items.Add(di.FullName))
        End Try
      End Sub
      Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim fb As New FolderBrowserDialog
        fb.Description = "Select Folder to work on"
        If Directory.Exists(TextBox1.Text) Then
          fb.SelectedPath = TextBox1.Text
        Else
          fb.SelectedPath = My.Computer.FileSystem.SpecialDirectories.MyDocuments
        End If
        If fb.ShowDialog = DialogResult.OK Then
          TextBox1.Text = fb.SelectedPath
        End If
      End Sub
      Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Select Case Button2.Text
          Case "GO"
            FileCount = 0
            Failed.Clear()
    
            Label6.Text = "0"
            Label7.Text = "0"
            Label8.Text = "0"
            ListBox1.Items.Clear()
            Label12.Text = "0"
            Label10.Text = "Working ....."
            Button2.Text = "STOP"
            sw.Start()
            BackgroundWorker1.RunWorkerAsync()
          Case Else
            BackgroundWorker1.CancelAsync()
        End Select
      End Sub
      Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Select Case Button3.Text
          Case "SHOW FAILED"
            ListBox2.BringToFront()
            Button3.Text = "SHOW RESULTS"
            Label9.Text = "Failed List"
          Case Else
            ListBox2.SendToBack()
            Button3.Text = "SHOW FAILED"
            Label9.Text = "Results List"
        End Select
      End Sub
    End Class


    Regards Les, Livingston, Scotland


    • Edited by leshay Saturday, August 24, 2019 2:44 PM
    • Marked as answer by wingers Saturday, August 24, 2019 10:24 PM
    Saturday, August 24, 2019 2:43 PM
  • @leshay

    Thank you - that seems to work well for me - and time to do whole of C: drive is comparable to running command in Powershell

    :)


    Darren Rose

    Saturday, August 24, 2019 10:24 PM
  • @dbasnett

    Hi, tried your code - had to change "TopDirectoryOnly" to "AllDirectories" as wanted to do a whole drive rather than just one folder level.

    It works for drives with not too many files / folders on, but if I try it on say my C: drive then Visual Studio doesn't like it and breaks out with an error I hadn't seen before:-

    "Managed Debugging Assistant 'ContextSwitchDeadlock' : 'The CLR has been unable to transition from COM context 0x12ca778 to COM context 0x12ca6c0 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.'"


    Darren Rose

    No change needed in the example I gave, it will iterate all directories and sub-directories. 

    The context deadlock is a warning and happens if you run something on the UI that takes a long time.


    Search Documentation

    SerialPort Info

    Multics - An OS ahead of its time.

     "Those who use Application.DoEvents have no idea what it does

        and those who know what it does never use it."    former MSDN User JohnWein


    • Edited by dbasnett Monday, August 26, 2019 2:25 PM
    Monday, August 26, 2019 12:57 PM