Datei-Zeitstempel auslesen und modifizieren

Veröffentlicht: 16. Aug 2001 | Aktualisiert: 13. Jun 2004

Von Mathias Schiffer

Das FileSystemObject-Objekt bietet Ihnen für Visual Basic einen bequemen Weg an, die drei Dateizeiten (Datum der Erzeugung, Datum der letzten Änderung und Datum des letzten Zugriffs) einer Datei auszulesen. Hierfür befragen Sie einfach die Eigenschaften DateCreated, DateLastModified und DateLastAccessed eines File-Objekts.

Das hilfreiche Objekt kapselt zum Auslesen der Datei-Zeitstempel einige API Funktionen – allen voran die Funktion GetFileTime, die drei übergebene Variable vom Typ FILETIME mit den entsprechenden Werten füllt:

Private Type FILETIME 
  lLowDateTime As Long 
  lHighDateTime As Long 
End Type 
Private Declare Function GetFileTime _ 
  Lib "kernel32" ( _ 
  ByVal hFile As Long, _ 
  ByRef lpCreationTime As Any, _ 
  ByRef lpLastAccessTime As Any, _ 
  ByRef lpLastWriteTime As Any _ 
  ) As Long

Da die FILETIME-Struktur keinen menschlich lesbaren Zeitstempel enthält, kann diese Darstellungsform mithilfe der Funktion FileTimeToSystemTime in eine SYSTEMTIME-Struktur überführt werden:

Private Type SYSTEMTIME 
  iYear As Integer 
  iMonth As Integer 
  iDayOfWeek As Integer 
  iDay As Integer 
  iHour As Integer 
  iMinute As Integer 
  iSecond As Integer 
  iMilliseconds As Integer 
End Type 
Private Declare Function FileTimeToSystemTime _ 
  Lib "kernel32" ( _ 
  ByRef lpFileTime As FILETIME, _ 
  ByRef lpSystemTime As SYSTEMTIME _ 
  ) As Long

Vor dieser Umwandlung ist jedoch zu beachten, dass die Zeitangaben nicht in der Ortszeit des Anwenders, sondern allgemein in "Greenwich Mean Time" (GMT) gehalten ist. Um diese Angabe in die lokale Ortszeit zu überführen, muss zunächst die Funktion FileTimeToLocalFileTime eingesetzt werden:

Private Declare Function FileTimeToLocalFileTime _ 
  Lib "kernel32" ( _ 
  ByRef lpFileTime As FILETIME, _ 
  ByRef lpLocalFileTime As FILETIME _ 
  ) As Long

Zuletzt wird noch ein Handle auf die Datei benötigt, das der Funktion GetFileTime im ersten Parameter (hFile) übergeben werden kann. Zu diesem Zweck wird die Datei mithilfe der Funktion CreateFile geöffnet (nach dem Zugriff wird sie mittels CloseHandle wieder geschlossen):

Private Declare Function CreateFile _ 
  Lib "kernel32" Alias "CreateFileA" ( _ 
  ByVal FileName As String, _ 
  ByVal DesiredAccess As Long, _ 
  ByVal ShareMode As Long, _ 
  ByRef lpSecurityAttributes As Any, _ 
  ByVal CreationDisposition As Long, _ 
  ByVal FlagsAndAttributes As Long, _ 
  ByVal hTemplateFile As Long _ 
  ) As Long 
Private Declare Function CloseHandle _ 
  Lib "kernel32" ( _ 
  ByVal hObject As Long _ 
  ) As Long 
Private Const GENERIC_READ     As Long = &H80000000 
Private Const GENERIC_WRITE    As Long = &H40000000 
Private Const FILE_SHARE_READ  As Long = &H1& 
Private Const FILE_SHARE_WRITE As Long = &H2& 
Private Const OPEN_EXISTING    As Long = &H3& 
Private Const FILE_FLAG_BACKUP_SEMANTICS As Long = &H2000000 
Private Const INVALID_HANDLE_VALUE       As Long = -&H1&

Mit dieser Sammlung von API Funktionen können wir den Zugriff auf Zeitstempel von Dateien nun vollziehen:

Dim FTDC As FILETIME   ' Datum der Erzeugung 
Dim FTLM As FILETIME   ' Datum der letzten Änderung 
Dim FTLA As FILETIME   ' Datum des letzten Zugriffs 
Dim STDC As SYSTEMTIME ' Erzeugungsdatum als SYSTEMTIME 
Dim STLM As SYSTEMTIME ' Änderungsdatum als SYSTEMTIME 
Dim STLA As SYSTEMTIME ' Zugriffsdatum als SYSTEMTIME 
Dim dtDC As Date       ' Erzeugungsdatum als Date-Variable 
Dim dtLM As Date       ' Änderungsdatum als Date-Variable 
Dim dtLA As Date       ' Zugriffsdatum als Date-Variable 
Dim hFile As Long      ' Handle auf Datei / Verzeichnis 
Dim RetVal As Long 
Dim sResult As String 
  ' Datei (nur unter Windows NT/2000 auch: Verzeichnis) 
  ' für Lesezugriff öffnen 
  hFile = CreateFile("c:\autoexec.bat", GENERIC_READ, _ 
                     FILE_SHARE_WRITE Or FILE_SHARE_READ, _ 
                     ByVal 0&, OPEN_EXISTING, _ 
                     FILE_FLAG_BACKUP_SEMANTICS, 0) 
  If hFile <> INVALID_HANDLE_VALUE Then ' Erfolgreich geöffnet 
    ' FILETIME-Zeitstempel auslesen: 
    RetVal = GetFileTime(hFile, FTDC, FTLA, FTLM) 
    ' Datei schließen 
    CloseHandle hFile 
    ' Von GMT-Zeiten in lokale Zeiten umwandeln: 
    RetVal = FileTimeToLocalFileTime(FTDC, FTDC) 
    RetVal = FileTimeToLocalFileTime(FTLM, FTLM) 
    RetVal = FileTimeToLocalFileTime(FTLA, FTLA) 
    ' Von FILETIME- in SYSTEMTIME-Strukturen überführen: 
    RetVal = FileTimeToSystemTime(FTDC, STDC) 
    RetVal = FileTimeToSystemTime(FTLM, STLM) 
    RetVal = FileTimeToSystemTime(FTLA, STLA) 
    ' Date-Variable aus SYSTEMTIME-Strukturen kreieren 
    With STDC 
      dtDC = DateSerial(.iYear, .iMonth, .iDay) _ 
           + TimeSerial(.iHour, .iMinute, .iSecond) 
    End With 
    With STLM 
      dtLM = DateSerial(.iYear, .iMonth, .iDay) _ 
           + TimeSerial(.iHour, .iMinute, .iSecond) 
    End With 
    With STLA 
      dtLA = DateSerial(.iYear, .iMonth, .iDay) _ 
           + TimeSerial(.iHour, .iMinute, .iSecond) 
    End With 
    ' Ergebnis ausgeben: 
    sResult = "Die Datei C:\AUTOEXEC.BAT hat folgende Zeitstempel:" 
    sResult = sResult & vbNewLine & vbNewLine 
    sResult = sResult & "Erzeugt am:      " & vbTab & CStr(dtDC) & vbCrLf 
    sResult = sResult & "Modifiziert am:  " & vbTab & CStr(dtLM) & vbCrLf 
    sResult = sResult & "Letzter Zugriff: " & vbTab & CStr(dtLM) 
    MsgBox sResult, vbInformation, "Zeitstempel-Information" 
  Else 
    MsgBox "Konnte nicht auf C:\AUTOEXEC.BAT zugreifen.", vbCritical 
  End If

Bis hierher hätten Sie die Aufgabe bei Bedarf auch einfacher mit dem FileSystemObject lösen können. Das Ändern der Zeitstempel ist über dieses Objekt jedoch nicht möglich. In diesem Fall spielt der API Ansatz seine Vorzüge aus: Das Vorgehen entspricht dem umgekehrten dargestellten Weg und wird dabei von entsprechenden API Funktionen unterstützt:

Private Declare Function SetFileTime _ 
  Lib "kernel32" ( _ 
  ByVal hFile As Long, _ 
  ByRef lpCreationTime As Any, _ 
  ByRef lpLastAccessTime As Any, _ 
  ByRef lpLastWriteTime As Any _ 
  ) As Long 
Private Declare Function SystemTimeToFileTime _ 
  Lib "kernel32" ( _ 
  ByRef lpSystemTime As SYSTEMTIME, _ 
  ByRef lpFileTime As FILETIME _ 
  ) As Long 
Private Declare Function LocalFileTimeToFileTime _ 
  Lib "kernel32" ( _ 
  ByRef lpLocalFileTime As FILETIME, _ 
  ByRef lpFileTime As FILETIME _ 
  ) As Long

Zum Setzen der Dateizeiten wird zunächst die Funktion SystemTimeToFileTime eingesetzt, um eine lesbare SYSTEMTIME-Struktur in eine FILETIME-Struktur zu überführen. Das Ergebnis dieser Umwandlung wird mittels LocalFileTimeToFileTime in GMT-Zeit gewandelt. Zuletzt werden die Zeitstempel mittels SetFileTime einer geöffneten Datei zugewiesen:

Dim dtDate As Date 
Dim ST As SYSTEMTIME 
Dim FT As FILETIME 
Dim hFile As Long 
Dim RetVal As Long 
  ' Einen willkürlichen Zeitpunkt (zur Vereinfachung 
  ' abkürzend für alle drei Zeitstempel) definieren: 
  dtDate = Now() 
  ' Überführung des Zeitpunkts in eine SYSTEMTIME-Struktur: 
  With ST 
    .iDay = Day(dtDate) 
    .iMonth = Month(dtDate) 
    .iYear = Year(dtDate) 
    .iHour = Hour(dtDate) 
    .iMinute = Minute(dtDate) 
    .iSecond = Second(dtDate) 
  End With 
  ' SYSTEMTIME-Struktur in eine FILETIME-Struktur wandeln: 
  RetVal = SystemTimeToFileTime(ST, FT) 
  ' FILETIME-Struktur in GMT-Zeitangabe umwandeln 
  RetVal = LocalFileTimeToFileTime(FT, FT) 
  ' Datei (nur unter Windows NT/2000 auch: Verzeichnis) 
  ' für Schreibzugriff öffnen 
  hFile = CreateFile("c:\autoexec.bat", GENERIC_WRITE, _ 
                    FILE_SHARE_WRITE Or FILE_SHARE_READ, _ 
                     ByVal 0&, OPEN_EXISTING, _ 
                     FILE_FLAG_BACKUP_SEMANTICS, 0) 
  ' Bei erfolgreichem Öffnen die Zeitstempel schreiben 
  If hFile <> INVALID_HANDLE_VALUE Then 
    RetVal = SetFileTime(hFile, FT, FT, FT) 
    CloseHandle hFile 
  Else 
    MsgBox "Konnte nicht auf C:\AUTOEXEC.BAT zugreifen.", vbCritical 
  End If