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