Zeitstempel für Dateien ermitteln und ändern mit VB6

Veröffentlicht: 30. Aug 2004 | Aktualisiert: 14. Nov 2004

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht? Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Auf dieser Seite

 Aus der Visual Basic Newsgroup microsoft.public.de.vb:
 Zeitstempel verändern per API

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Ich suche nach einer Möglichkeit, mit Visual Basic 6.0 die drei Zeitstempel einer Datei (Zeitpunkte der Erzeugung, Änderung und des letzten Zugriffs) auszulesen und auch zu verändern. Wie geht das?

Unter Visual Basic 6.0 können Sie mithilfe der Funktion FileDateTime den Zeitpunkt der Erstellung bzw. letzten Änderung einer Datei ermitteln. Dies entspricht dem Zeitstempel der letzten Veränderung (der ohne Veränderung dem Erstellungszeitpunkt entspricht, andernfalls aber abweicht).

Brauchen Sie zusätzliche Informationen, können Sie auf das "File System Object" zurückgreifen, das sich als Verweis auf die "Microsoft Scripting Runtime" einbinden lässt: Es unterstützt mit seinen Eigenschaften DateCreated, DateLastModified und DateLastAccessed für File- und Folder-Objekte die detaillierte Abfrage der Zeitstempel.

Weder Visual Basic 6.0 noch das "File System Object" erlauben Ihnen eine Veränderung der betreffenden Zeitstempel. Hier kommen Sie nur mit Hilfe des Win32-API zum Erfolg.

 

Zeitstempel verändern per API

Das Win32 API stellt die Funktionen GetFileTime und SetFileTime zur Verfügung, um die drei Zeitstempel auslesen und bearbeiten zu können.

Ein wenig Hintergrundwissen ist für ihre Verwendung jedoch erforderlich: Die Zeitstempel einer Datei werden in einem Dateizeitenformat vorgehalten (FILETIME), das in ein für Visual Basic nutzbares Zeitformat umgewandelt werden muss.

Hinzu kommt noch, dass Dateizeiten in der UTC-Zeitzone verwendet werden ("Universal Coordinated Time", außerhalb der U.S.A. besser bekannt als GMT = "Greenwich Mean Time").

Doch auch hierfür bietet das Win32-API Lösungen an: Die Funktion LocalFileTimeToFileTime erledigt für Dateizeitstempel den Übergang von der lokalen Zeit in die UTC-Zeitzone, während ihr Gegenstück FileTimeToLocalFileTime dabei hilft, aus einem UTC-Dateizeitstempel einen lokalen Dateizeitstempel zu erhalten.

Um eine Dateizeit in eine Systemzeit zu wandeln, bietet das Win32-API die Funktionen FileTimeToSystemTime und SystemTimeToFileTime an: Sie konvertieren Zeitangaben zwischen den Typen SYSTEMTIME und FILETIME.

Mit diesen Funktionen können Sie Zeitstempel nicht nur beliebig auslesen, sondern sie auch verändern. Der folgende Beispielcode liefert Ihnen eine Fertiglösung, die Sie einfach per "Copy & Paste" in Ihre Anwendungen übernehmen können.

Tipp: Kopieren Sie den Quelltext von Ihrem Webbrowser aus zunächst in WRITE.EXE und erst von dort aus in Ihre Entwicklungsumgebung, um den Verlust von Zeilenumbrüchen zu vermeiden.

' --- Notwendige Win32-API Deklarationen (Funktionen, Konstante, Typen, Aufzählungen):
  
Private Declare Function OpenFile Lib "kernel32" ( _
  ByVal lpFileName As String, _
  ByRef lpReOpenBuff As OFSTRUCT, _
  ByVal wStyle As Long _
  ) As Long
Private Declare Function CloseHandle _
  Lib "kernel32" ( _
  ByVal hObject As Long _
  ) As Long
  
' As Any-Deklaration von SetFileTime (fuer gewöhnlich
' FILETIME-Parameter, die aber zu NULL gesetzt werden können,
' um die entsprechende Information zu ignorieren
Private Declare Function SetFileTimeAPI _
  Lib "kernel32" Alias "SetFileTime" ( _
  ByVal hFile As Long, _
  ByRef lpCreationTime As Any, _
  ByRef lpLastAccessTime As Any, _
  ByRef lpLastWriteTime As Any _
  ) As Long
' Gegenstück:
Private Declare Function GetFileTimeAPI _
  Lib "kernel32" Alias "GetFileTime" ( _
  ByVal hFile As Long, _
  ByRef lpCreationTime As Any, _
  ByRef lpLastAccessTime As Any, _
  ByRef lpLastWriteTime As Any _
  ) As Long
  
' Lokale Dateizeit in eine universale Dateizeit übersetzen
Private Declare Function LocalFileTimeToFileTime _
  Lib "kernel32" ( _
  ByRef lpLocalFileTime As FILETIME, _
  ByRef lpFileTime As FILETIME _
  ) As Long
' Gegenstück:
Private Declare Function FileTimeToLocalFileTime _
  Lib "kernel32" ( _
  ByRef lpFileTime As FILETIME, _
  ByRef lpLocalFileTime As FILETIME _
  ) As Long
  
' Eine SYSTEMTIME-Struktur in eine FILETIME übersetzen
Private Declare Function SystemTimeToFileTime _
  Lib "kernel32" ( _
  ByRef lpSystemTime As SYSTEMTIME, _
  ByRef lpFileTime As FILETIME _
  ) As Long
' Gegenstück:
Private Declare Function FileTimeToSystemTime _
  Lib "kernel32" ( _
  ByRef lpFileTime As FILETIME, _
  ByRef lpSystemTime As SYSTEMTIME _
) As Long
  
Private Const OF_READ = &H0
Private Const OF_READWRITE = &H2
Private Const OFS_MAXPATHNAME = 128
  
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 Type OFSTRUCT
  cBytes As Byte
  fFixedDisk As Byte
  nErrCode As Integer
  Reserved1 As Integer
  Reserved2 As Integer
  szPathName(OFS_MAXPATHNAME) As Byte
End Type
  
Public Enum FileTimeEnum
  mftCreationTime = 1
  mftLastAccessTime = 2
  mftLastWriteTime = 4
End Enum
  
  
' --- Code
  
  
Public Function GetFileTime(ByVal Pfad As String, _
                            ByVal TimeToGet As FileTimeEnum _
                           ) As Date
' Ermittelt einen der drei Zeitstempel einer Datei/eines Verzeichnisses
' und gibt diesen als Visual Basic Date-Variable zurück.
Dim FTCreationTime As FILETIME, SysTime As SYSTEMTIME
Dim FTLastAccessTime As FILETIME
Dim FTLastWriteTime As FILETIME
Dim SelectedTime As FILETIME
Dim OFS As OFSTRUCT, hFile As Long
  
  ' Versuchen, die betroffene Datei zu öffnen
  hFile = OpenFile(Pfad, OFS, OF_READ)
  If hFile = 0 Then Exit Function ' OpenFile ist gescheitert => Ausgang
  ' Ermitteln der Zeitstempel
  GetFileTimeAPI hFile, FTCreationTime, FTLastAccessTime, FTLastWriteTime
  CloseHandle hFile
  
  ' Gesuchten Zeitstempel auswählen
  Select Case TimeToGet
    Case mftCreationTime: SelectedTime = FTCreationTime
    Case mftLastAccessTime: SelectedTime = FTLastAccessTime
    Case mftLastWriteTime: SelectedTime = FTLastWriteTime
  End Select
  
  ' Umsetzung in lokale Systemzeit
  FileTimeToLocalFileTime SelectedTime, SelectedTime
  FileTimeToSystemTime SelectedTime, SysTime
  
  ' Rückgabe als VB-Date
  With SysTime
    GetFileTime = _
      DateSerial(.wYear, .wMonth, .wDay) + _
      TimeSerial(.wHour, .wMinute, .wSecond)
  End With
  
End Function
  
  
Public Function SetFileTimeByDate(ByVal Pfad As String, _
                                  ByVal TimeToModify As FileTimeEnum, _
                                  ByVal DateToSet As Date)
' Setzt den Zeitstempel einer Datei unter Zuhilfenahme
' der ausführenden Funktion SetFileTime.
  
  SetFileTimeByDate = SetFileTime(Pfad, TimeToModify, _
                                  Day(DateToSet), Month(DateToSet), Year(DateToSet), _
                                  Hour(DateToSet), Minute(DateToSet), Second(DateToSet))
  
End Function
  
  
Private Function SetFileTime(ByVal Pfad As String, _
                             ByVal TimeToModify As FileTimeEnum, _
                             ByVal Tag As Integer, _
                             ByVal Monat As Integer, _
                             ByVal Jahr As Integer, _
                             ByVal Stunde As Integer, _
                             ByVal Minute As Integer, _
                             ByVal Sekunde As Integer _
                             ) As Boolean ' True => Erfolg
  
Dim FT As FILETIME, ST As SYSTEMTIME
Dim OFS As OFSTRUCT, hFile As Long, RetVal As Long
  
  ' Dateizeiten (FILETIME) und Systemzeiten (SYSTEMTIME)
  ' unterscheiden sich im Format. Zunaechst wird eine
  ' SYSTEMTIME-Struktur mit den uebergebenen Parametern gefüllt,
  ' danach wird sie in eine FILETIME konvertiert. Da Dateizeiten
  ' GMT-orientiert geschrieben werden, ist danach noch eine Anpassung
  ' an die GMT-Zeitzone erforderlich.
  
  ' SYSTEMTIME-Struktur ausfüllen
  With ST
    .wYear = Jahr
    .wMonth = Monat
    .wDay = Tag
    .wHour = Stunde
    .wMinute = Minute
    .wSecond = Sekunde
    '.wMilliseconds = 0
  End With
  
  ' Lokale Systemzeit in lokale Dateizeit konvertieren
  RetVal = SystemTimeToFileTime(ST, FT)
  If RetVal = 0 Then Exit Function  ' Pech gehabt
  
  ' Lokale Dateizeit in GMT-Dateizeit konvertieren
  RetVal = LocalFileTimeToFileTime(FT, FT)
  If RetVal = 0 Then Exit Function  ' Pech gehabt
  
  ' Datei fuer Lese- und Schreibzugriff öffnen
  hFile = OpenFile(Pfad, OFS, OF_READWRITE)
  If hFile = 0 Then Exit Function ' Pech gehabt
  
  ' Eine Datei hat 3 Dateizeiten:
  ' Erzeugung, Letzter Zugriff, Letzte Speicherung.
  ' Eine Zeit davon soll geändert werden, der Rest soll
  ' identisch bleiben. Dank "As Any"-Deklaration werden
  ' nicht zu ändernde Zeitparameter mit "ByVal 0&" (für
  ' NULL) bedient.
  
  If (TimeToModify And mftCreationTime) > 0 Then
    RetVal = SetFileTimeAPI(hFile, FT, ByVal 0&, ByVal 0&)
    If RetVal = 0 Then CloseHandle hFile: Exit Function ' Pech gehabt
  End If
  
  If (TimeToModify And mftLastAccessTime) > 0 Then
    RetVal = SetFileTimeAPI(hFile, ByVal 0&, FT, ByVal 0&)
    If RetVal = 0 Then CloseHandle hFile: Exit Function ' Pech gehabt
  End If
  
  If (TimeToModify And mftLastWriteTime) > 0 Then
    RetVal = SetFileTimeAPI(hFile, ByVal 0&, ByVal 0&, FT)
    If RetVal = 0 Then CloseHandle hFile: Exit Function ' Pech gehabt
  End If
  
  ' Handle schließen
  CloseHandle hFile
  
  SetFileTime = True
  
End Function
  
' ---