Solved

Last Accessed file attribute

Posted on 2002-06-25
14
301 Views
Last Modified: 2007-12-19
I've been tring to modify the last accessed file attribute on about 400,000 files.

The API reference includes SetFileTime - which looked good.

Searching the web for examples I found many, all using this call in the same way:

hFile = OpenFile (fName,...
SetFileTime hFile, newCreateTime, newAccessTime, newModifyTime
CloseFile hFile

Which only kinda works - I've modified the above to add msgboxes to follow progress, and what happens is that the SetFileTime can actually change the Last Accessed attribute, but the CloseFile "touches" the file and sets the Last Accessed attribute to the current system time.

The only way I've been able to acheive what I want is nasty - I change the system time, open the file, close the file, reset the system time.

Someone has suggested using FindFirstFile to get a handle to pass to SetFileTime, but I can't get this to work.

Anyone able to help me with this?

The best I've got so far is:

Private Sub Command1_Click()

  'variables required
   Dim hFile As Long
   Dim fName As String
   
  'structures required
   Dim OFS As OFSTRUCT
   Dim FT_CREATE As FILETIME
   Dim FT_ACCESS As FILETIME
   Dim FT_WRITE As FILETIME
   
  'assign the textbox entry to the filename
   fName = Text1
   
  'open the file
   hFile = OpenFile(fName, OFS, OF_READWRITE)
   
  'get the FILETIME info for the created, accessed and last write info
   Call GetFileTime(hFile, FT_CREATE, FT_ACCESS, FT_WRITE)
   
  'set all times to last write time
   Call SetFileTime(hFile, FT_WRITE, FT_WRITE, FT_WRITE)
   
  'clean up by closing the file
   Call CloseHandle(hFile)

End Sub
0
Comment
Question by:nedrub
  • 6
  • 4
  • 2
  • +2
14 Comments
 
LVL 43

Accepted Solution

by:
TimCottee earned 100 total points
ID: 7107908
Here is an example of this, that doesn't use OpenFile/CloseFile.

 'This project needs a Common Dialog box, named CDBox.
'  (To add the Common Dialog Box to your tools menu, go to Project->Components (or press CTRL-T)
'   and select Microsoft Common Dialog control)
Private Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type
    Private Type SYSTEMTIME
    wYear As Integer
    wMonth As Integer
    wDayOfWeek As Integer
    wDay As Integer
    wHour As Integer
    wMinute As Integer
    wSecond As Integer
    wMilliseconds As Integer
End Type
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FILETIME) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpLocalFileTime As FILETIME, lpFileTime As FILETIME) As Long
Private Sub Form_Load()
    'KPD-Team 1998
    'URL: http://www.allapi.net/
    'KPDTeam@Allapi.net
    Dim m_Date As Date, lngHandle As Long
    Dim udtFileTime As FILETIME
    Dim udtLocalTime As FILETIME
    Dim udtSystemTime As SYSTEMTIME
    m_Date = Format(Now, "DD-MM-YY")

    'Set the dialog's title
    CDBox.DialogTitle = "Choose a file ..."
    'Set the dialog's filter
    CDBox.Filter = "All Files (*.*)|*.*"
    'Show the 'Open File'-dialog
    CDBox.ShowOpen

    udtSystemTime.wYear = Year(m_Date)
    udtSystemTime.wMonth = Month(m_Date)
    udtSystemTime.wDay = Day(m_Date)
    udtSystemTime.wDayOfWeek = WeekDay(m_Date) - 1
    udtSystemTime.wHour = Hour(m_Date)
    udtSystemTime.wMinute = Minute(m_Date)
    udtSystemTime.wSecond = Second(m_Date)
    udtSystemTime.wMilliseconds = 0

    ' convert system time to local time
    SystemTimeToFileTime udtSystemTime, udtLocalTime
    ' convert local time to GMT
    LocalFileTimeToFileTime udtLocalTime, udtFileTime
    ' open the file to get the filehandle
    lngHandle = CreateFile(CDBox.Filename, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
    ' change date/time property of the file
    SetFileTime lngHandle, udtFileTime, udtFileTime, udtFileTime
    ' close the handle
    CloseHandle lngHandle
    MsgBox "The date of the file '" + CDBox.Filename + "' has been changed to" + Str$(m_Date), vbInformation + vbOKOnly, App.Title
End Sub

Instead of using the common dialog to get the file name, you could use the DIR() function to get the file name (or any other method of iterating the files that you are interested in). And pass this to a modified version of this sample.
0
 

Author Comment

by:nedrub
ID: 7107983
Thanks Tim, but it doesn't work for me - I run the program, select a file, am told that the access date has been changed to 2026 - but when I look at the file's properties through Explorer I see today's date.

I assume that the CloseHandle call is modifying the last accessed attribute.
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 7108117
Changed

m_Date = Format(Now, "DD-MM-YY")

to

m_Date = Format(Now, "DD-MM-YYYY")
0
 

Author Comment

by:nedrub
ID: 7108154
As setting the date to today's date doesn't test whether the close is "touching" the file, I've modified the code above:

m_Date = Format(Now, "DD-MM-YY")

to

m_Date = Format(Now + 2, "DD-MM-YYYY")

After running the program I check the file's properties via explorer:

Created: 27 June 2002 (desired)
Modified: 27 June 2002 (desired)
Accessed: 25 June 2002 (not desired)

As SetFileTime is called thus:

   SetFileTime lngHandle, udtFileTime, udtFileTime, udtFileTime

(ie with the same time & date for all three attributes), I can only assume that the CloseHandle call is setting the Last Accessed attribute to the current time & date.

How can I close the handle without modifying the Last Accessed attribute?

OR

Is there another way of changing the a file's Last Accessed attribute which does not use CloseHandle?
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 7108202
Try this


Option Explicit

'This project needs a Common Dialog box, named CDBox.
'  (To add the Common Dialog Box to your tools menu, go to Project->Components (or press CTRL-T)
'   and select Microsoft Common Dialog control)
Private Type FILETIME
   dwLowDateTime As Long
   dwHighDateTime As Long
End Type
   Private Type SYSTEMTIME
   wYear As Integer
   wMonth As Integer
   wDayOfWeek As Integer
   wDay As Integer
   wHour As Integer
   wMinute As Integer
   wSecond As Integer
   wMilliseconds As Integer
End Type
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FILETIME) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpLocalFileTime As FILETIME, lpFileTime As FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long

Private Sub Command1_Click()
'KPD-Team 1998
   'URL: http://www.allapi.net/
   'KPDTeam@Allapi.net
   Dim lngHandle As Long
   Dim ft1 As FILETIME
   Dim ft2 As FILETIME
   Dim ft3 As FILETIME
   Dim ft4 As FILETIME
   Dim st1 As SYSTEMTIME

   'Set the dialog's title
   CDBox.DialogTitle = "Choose a file ..."
   'Set the dialog's filter
   CDBox.Filter = "All Files (*.*)|*.*"
   'Show the 'Open File'-dialog
   CDBox.ShowOpen

    lngHandle = CreateFile(CDBox.FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
    GetFileTime lngHandle, ft1, ft2, ft3
    'Convert the file time to the local file time
    FileTimeToLocalFileTime ft3, ft4
    'Convert the file time to system file time
    FileTimeToSystemTime ft4, st1
    MsgBox "The selected file was last modified on" + Str$(st1.wMonth) + "/" + LTrim(Str$(st1.wDay)) + "/" + LTrim(Str$(st1.wYear))
    'Close the file
    CloseHandle lngHandle
End Sub

0
 

Author Comment

by:nedrub
ID: 7108256
EDDYKT,

Thanks, but your code reads the Last Modified attribute and displays it.

What I want to do is CHANGE the Last ACCESSED attribute to a given time & date (other than the current time and date) - e.g. yesterday's date.

I'm told that SetFileTime is the API call to make, research in MSDN shows that this needs a handle which must have at least GENERIC_WRITE access.

That is easy enough, and works. But afterwards I need to close the handle. Using CloseHandle sets the LastAccessed attribute to the current time and date.

I need another method of changing the Last Accessed attribute, or a method of closing a file handle which doesn't set the Last Accessed attribute.
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 7108291
To combined my code and Tim's code


Option Explicit

'This project needs a Common Dialog box, named CDBox.
'  (To add the Common Dialog Box to your tools menu, go to Project->Components (or press CTRL-T)
'   and select Microsoft Common Dialog control)
Private Type FILETIME
   dwLowDateTime As Long
   dwHighDateTime As Long
End Type
   Private Type SYSTEMTIME
   wYear As Integer
   wMonth As Integer
   wDayOfWeek As Integer
   wDay As Integer
   wHour As Integer
   wMinute As Integer
   wSecond As Integer
   wMilliseconds As Integer
End Type
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function SetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function SystemTimeToFileTime Lib "kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FILETIME) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function LocalFileTimeToFileTime Lib "kernel32" (lpLocalFileTime As FILETIME, lpFileTime As FILETIME) As Long

Private Declare Function GetFileTime Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib "kernel32" (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib "kernel32" (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long



Private Sub Form_Load()
   'KPD-Team 1998
   'URL: http://www.allapi.net/
   'KPDTeam@Allapi.net
   Dim m_Date As Date, lngHandle As Long
   Dim udtFileTime As FILETIME
   Dim udtLocalTime As FILETIME
   Dim udtSystemTime As SYSTEMTIME
   m_Date = Format(DateAdd("d", -2, Now), "DD-MM-YYYY")

   'Set the dialog's title
   CDBox.DialogTitle = "Choose a file ..."
   'Set the dialog's filter
   CDBox.Filter = "All Files (*.*)|*.*"
   'Show the 'Open File'-dialog
   CDBox.ShowOpen

   udtSystemTime.wYear = Year(m_Date)
   udtSystemTime.wMonth = Month(m_Date)
   udtSystemTime.wDay = Day(m_Date)
   udtSystemTime.wDayOfWeek = Weekday(m_Date) - 1
   udtSystemTime.wHour = Hour(m_Date)
   udtSystemTime.wMinute = Minute(m_Date)
   udtSystemTime.wSecond = Second(m_Date)
   udtSystemTime.wMilliseconds = 0

   ' convert system time to local time
   SystemTimeToFileTime udtSystemTime, udtLocalTime
   ' convert local time to GMT
   LocalFileTimeToFileTime udtLocalTime, udtFileTime
   ' open the file to get the filehandle
   lngHandle = CreateFile(CDBox.FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
   ' change date/time property of the file
   SetFileTime lngHandle, udtFileTime, udtFileTime, udtFileTime
   ' close the handle
   CloseHandle lngHandle
   MsgBox "The date of the file '" + CDBox.FileName + "' has been changed to" + Str$(m_Date), vbInformation + vbOKOnly, App.Title
End Sub

Private Sub Command1_Click()
'KPD-Team 1998
  'URL: http://www.allapi.net/
  'KPDTeam@Allapi.net
  Dim lngHandle As Long
  Dim ft1 As FILETIME
  Dim ft2 As FILETIME
  Dim ft3 As FILETIME
  Dim ft4 As FILETIME
  Dim st1 As SYSTEMTIME

  'Set the dialog's title
  CDBox.DialogTitle = "Choose a file ..."
  'Set the dialog's filter
  CDBox.Filter = "All Files (*.*)|*.*"
  'Show the 'Open File'-dialog
  CDBox.ShowOpen

   lngHandle = CreateFile(CDBox.FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
   GetFileTime lngHandle, ft1, ft2, ft3
   'Convert the file time to the local file time
   FileTimeToLocalFileTime ft3, ft4
   'Convert the file time to system file time
   FileTimeToSystemTime ft4, st1
   MsgBox "The selected file was last modified on" + Str$(st1.wMonth) + "/" + LTrim(Str$(st1.wDay)) + "/" + LTrim(Str$(st1.wYear))
   'Close the file
   CloseHandle lngHandle
End Sub



You has set the date to
ie.

m_Date = Format(DateAdd("d", -2, Now), "DD-MM-YYYY")

2 days before current day
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:nedrub
ID: 7108372
EDDYKT,

Your code is still reading LAST MODIFIED, I want LAST ACCESSED.

I've changed your code to that below (have changed only two lines, the text in the message box, and passing ft2 instead of ft3 to FileTimeToLocalFileTime).

Upon form load, the combined program modifies all three date properties, but the CloseHandle then modifies the last accessed attribute to the current time. The command button then displays a dialog box confirming that the last access was today.

I've also modified Form_Load so that Command1_Click is called just before and just after CloseHandle. This confirms that the Last Accessed date is changed to two days ago, but then changed to the current date by the CloseHandle.

------------------------------------
Modified code to read LAST ACCESSED
------------------------------------
Private Sub Command1_Click()
'KPD-Team 1998
 'URL: http://www.allapi.net/
 'KPDTeam@Allapi.net
 Dim lngHandle As Long
 Dim ft1 As FILETIME
 Dim ft2 As FILETIME
 Dim ft3 As FILETIME
 Dim ft4 As FILETIME
 Dim st1 As SYSTEMTIME

 'Set the dialog's title
 CDBox.DialogTitle = "Choose a file ..."
 'Set the dialog's filter
 CDBox.Filter = "All Files (*.*)|*.*"
 'Show the 'Open File'-dialog
 CDBox.ShowOpen

  lngHandle = CreateFile(CDBox.FileName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
  GetFileTime lngHandle, ft1, ft2, ft3
  'Convert the file time to the local file time
  FileTimeToLocalFileTime ft2, ft4
  'Convert the file time to system file time
  FileTimeToSystemTime ft4, st1
  MsgBox "The selected file was last accessed on" + Str$(st1.wMonth) + "/" + LTrim(Str$(st1.wDay)) + "/" + LTrim(Str$(st1.wYear))
  'Close the file
  CloseHandle lngHandle
End Sub
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 7108577
nedrub, sorry to say this, but I think that's how the last accessed property works.   You could set the system time/date first in code (caching the existing date/time in order to set it back after.)

It's a horrible kludge, but I think it is the only thing that will work.
0
 

Author Comment

by:nedrub
ID: 7108622
Paul,

Yeah, that's where I started the post.

I just can't believe they bothered to include the last accessed attribute in the SetFileTime procedure if whatever you put in there gets clobbered by the CloseHandle that you have to have!
0
 
LVL 26

Expert Comment

by:EDDYKT
ID: 7108653
Try this

You need to add Microsoft scripting Runtime from your references

Option Explicit

Private Sub Command1_Click()
FileAttribute ("c:\temp")
End Sub
Private Sub FileAttribute(FileName)
    Dim fso
    Dim folder
    Dim Files1
    Dim File1
    Dim SubFolders
    Dim SubFolder
   
    On Error Resume Next
    If (Dir$(FileName, vbDirectory) = "") Then Exit Sub
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set folder = fso.GetFolder(FileName)
   
    Set SubFolders = folder.SubFolders
    If SubFolders.Count <> 0 Then
        For Each SubFolder In SubFolders
            FileAttribute (SubFolder)
        Next
    End If
   
    Set Files1 = folder.Files
    If Files1.Count <> 0 Then
        For Each File1 In Files1
            Debug.Print File1.Name, File1.DateLastAccessed
        Next
    End If
End Sub

0
 

Author Comment

by:nedrub
ID: 7108733
Ah! Was running on a FAT32 partition. Tried it on another machine with NTFS 2000 and it works!
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 7108815
hearing...
0
 
LVL 38

Expert Comment

by:PaulHews
ID: 7108846
Interesting. :)
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now