HERBERS
Excel-Forum
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Entdecke rund 2 Millionen Excel-Lösungen im
Forumsarchiv

Beiträge zum Thread: VBA - Dateien umbenennen je nach Dateiegenschaft

Case
20.05.2026 21:09:20
Du könntest es auch...
Christian
20.05.2026 22:00:40
AW: Du könntest es auch...
Case
21.05.2026 07:58:15
Ja - mit...
schauan
20.05.2026 22:45:44
AW: Du könntest es auch...
Christian
20.05.2026 23:14:52
AW: Du könntest es auch...
Christian
20.05.2026 23:15:33
dein Vorschlag
Christian
21.05.2026 11:22:16
AW: Du könntest es auch...
Christian
22.05.2026 18:27:17
erstmal ungetestet
snb
23.05.2026 00:00:52
AW: erstmal ungetestet
Case
24.05.2026 08:58:40
Irgendwo habe...
Christian
24.05.2026 11:07:26
AW: Irgendwo habe...
Case
24.05.2026 16:03:07
Nun - ich habe mir...
Christian
24.05.2026 17:44:42
AW: Nun - ich habe mir...
Case
24.05.2026 17:59:34
Also der...
Christian
24.05.2026 18:24:31
tut mir leid
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 19:02:49
VBA - Dateien umbenennen je nach Dateiegenschaft
Hallo,

ich wollte mal fragen, ob das hier mit VBA möglich ist, ich frage nach VBA, weil ich es in ein bestehendes Makro einbauen will, welches u.a. dann im nächsten Schritt die entsprechende PQ Abfrage aktualisiert und die Daten weiterverarbeitet.

Jedenfalls was ich mir vorstelle, die 3 neuesten csv-Dateien in meinem Download Ordner sollen umbenannt werden, die größte in L1.csv, die zweitgrößte in L2.csv und die kleinste der dreien in L3.csv

Ist das mit VBA lösbar?

Danke
Chrisian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
daniel
20.05.2026 20:12:10
AW: VBA - Dateien umbenennen je nach Dateiegenschaft
Hi

ja, kann man machen.

schau dir mal den Beispielcode an.

da ich zum bestimmen der neusten und größten Dateien das Sortieren verwende und Sortieren in einem Excelblatt einfacher ist als in Arrays innerhalb von VBA benötigst du ein freies Tabellenblatt in dem die Namen, Dateigröße und erstelldatum eingetragen werden können.

Sub test()

Dim Datei As String
Dim Pfad As String

Pfad = "C:\Test\"

Datei = Dir(Pfad & "*.csv")

With Sheets("Tabelle1")
.Cells.Clear
'--- CSV-Dateien aus verzeichnis lesen
Do Until Datei = ""
With .Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0)
.Offset(0, 0).Value = Datei
.Offset(0, 1).Value = FileDateTime(Pfad & Datei)
.Offset(0, 2).Value = FileLen(Pfad & Datei)
End With
Datei = Dir
Loop
With .Cells(2, 1).CurrentRegion
'neuste Dateien über sortieren bestimmen (neusten nach oben)
.Sort key1:=.Cells(1, 2), order1:=xlDescending, Header:=xlNo
'--- oberen drei nach größe sortieren
.Resize(3).Sort key1:=.Cells(1, 3), order1:=xlDescending, Header:=xlNo

Name Pfad & .Cells(1, 1) As Pfad & "L1.csv"
Name Pfad & .Cells(2, 1) As Pfad & "L2.csv"
Name Pfad & .Cells(3, 1) As Pfad & "L3.csv"
End With
.Cells.Clear
End With


End Sub


FileDateTime gibt dir das letzte Speicherdatum der Datei

Dateien mit den neuen Namen (L1, L2 ) sollten nicht vorhanden sein.
Falls doch, müsstest du die vorher löschen oder umbenennen, oder das Makro um eine entsprechende Prüfung erweitern.

Gruß Daniel
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 20:44:39
AW: VBA - Dateien umbenennen je nach Dateiegenschaft
Hallo Daniel,

hab's noch ein bissl an meine Gegebenheiten angepasst, z.b. Download Ordner, dann hat es in der Testdatei, in der nur dieses Makro lief, funktioniert.
Einen geeingeten Platz zu finden, wo ich das in der Originaldatei reinschreiben kann, wird jetzt ne etwas umfangreichere Sache, ich hab zwar extra ein Blatt in der Mappe für temporär angelegte Sachen, aber werde jetzt mal prüfen müssen, wo genau zu dem zeitpunkt wo ich das ins Makro einfügen will in diesem Blatt schon Spalten/Zeilen in Beschlag sind und wo nicht, dass da nix überschrieben wird.
Aber zurück zum Thema, ich denke das bekomme ich hin, ich bedanke mich bei dir und wünsche dir noch einen schönen Abend
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
daniel
20.05.2026 20:53:33
AW: VBA - Dateien umbenennen je nach Dateiegenschaft
wenn du ein schon vorhandenes Blatt nutzen willst, dann leere halt nicht das ganze Blatt, sondern nur den Bereich, den du hierfür vorgesehen hast.
beachte aber immer den Mindestabstand mit einer komplett leeren Spalte zu anderen Bereichen, damit das .CurrentRegion auch richtig arbeiten kann.

Gruß Daniel
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 21:51:52
AW: VBA - Dateien umbenennen je nach Dateiegenschaft
Hallo Daniel,

das ist kein Problem, ich meinte nur, ich muss das große Makro mal laufen lassen und an dem Punkt wo ich deinen Code einfügen will mal anhalten, um zu sehen, was zu dem Zeitpunkt wo in dem Blatt steht, weil wie gesagt da kommen nur temporäre Sachen rein, bei so großen Makros weiß ich das nicht aus dem Kopf.

Aber danke für die Hilfe
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Case
20.05.2026 21:09:20
Du könntest es auch...
Moin Christian, :-)

... mit PowerShell probieren: ;-)
Option Explicit

Public Sub Main()
Dim strPS As String
Dim strDL As String
strDL = Environ$("USERPROFILE") & "\Downloads"
strPS = "$strDL='" & strDL & "';"
strPS = strPS & "Remove-Item (Join-Path $strDL ""L*.csv"") -ErrorAction SilentlyContinue;"
strPS = strPS & "$files=Get-ChildItem $strDL -Filter *.csv | Sort LastWriteTime -Descending | Select -First 3 | Sort Length -Desc;"
strPS = strPS & "$i=1;"
strPS = strPS & "foreach($f in $files){Rename-Item $f.FullName ('L'+$i+'.csv') -Force;$i++}"
Shell "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command " & Chr(34) & strPS & Chr(34), vbHide 'vbNormalFocus
End Sub

Das geht auch als "Einzeiler", aber so ist es übersichtlicher. ;-)
Ist getestet. ;-)

Servus
Case
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 22:00:40
AW: Du könntest es auch...
Hallo Case,

auch dir vielen Dank. Wieder was gelernt, ich wusste zwar dass ich Powershell Scripte aus VBA heraus starten kann, aber das man den Inhalt des Scripts auch in VBA schreiben kann und dann nur noch den Powershell Befehl ausführen kann, war mir neu.

Auf jedenfall funktionierts danke
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Case
21.05.2026 07:58:15
Ja - mit...
Moin Christian, :-)

... PowerShell lassen sich schon viele Aktionen ausführen: ;-)
https://learn.microsoft.com/de-de/powershell/
https://learn.microsoft.com/de-de/powershell/scripting/samples/sample-scripts-for-administration?view=powershell-7.6

Früher hatte ich "haufenweise" *.ps1 Dateien/Skripte - Doppelklick und fertig. ;-)

Servus
Case
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
schauan
20.05.2026 22:45:44
AW: Du könntest es auch...
Hallöchen,

mal ohne umbenennen eine Liste der 3 neuesten Files mit Größe und Datum.
Problem: Wenn ich das auf csv einschränken will, kommt bei mir der McAfee :-(

Sub Letzte_3()


Dim arr3() As String

arr3 = Split(CreateObject("WScript.Shell").Exec( _
"powershell -command ""Get-ChildItem 'C:\Temp' -File | " & _
"Sort-Object LastWriteTime -Descending | " & _
"Select-Object -First 3 Name,Length,LastWriteTime | " & _
"ForEach-Object { $_.Name + '|' + $_.Length + '|' + $_.LastWriteTime.ToString() }""" _
).StdOut.ReadAll, vbLf)

With Range("A1").Resize(UBound(arr3) + 1)
.Value = Application.Transpose(arr3)
.TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
:="|", FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), _
TrailingMinusNumbers:=True
End With

End Sub


Hinweis:
Man hätte ggf. ein generelles Problem bei Postscript oder anderen Scriptsprachen, wenn die Nutzung in Firmen eingeschränkt ist.
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 23:14:52
AW: Du könntest es auch...
Hallo schauan,

danke für deine Hinweise. Ich nutze weder McAfee noch ist die Datei in irgendeiner Firma. Aber trotzdem danke
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
20.05.2026 23:15:33
dein Vorschlag
schaue ich mir morgen genauer an, mir fallen die Augen zu.
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
21.05.2026 11:22:16
AW: Du könntest es auch...
Hallo schauan,

wenn ich deinen Code richtig verstehe, durchsucht er C:\Temp, findet die 3 neuesten Dateien, holt Name, Größe und Änderungsdatum und schreibt alles formatiert in Excel.

Werde jetzt mal schaun, welche der Lösungswege für mich am praktischsten ist. Das bekomme ich denke ich alleine hin.
Vielen Dank euch nochmal
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
snb
22.05.2026 11:53:41
AW: VBA - Dateien umbenennen je nach Dateiegenschaft
teste mal:

Sub M_snb()

c00 = "D:\SNB_\"

sn = Split(CreateObject("wscript.shell").Exec("cmd /c dir " & c00 & "*.csv /a/b/o-d").StdOut.ReadAll, vbCrLf)
st = Array(FileLen(c00 & sn(0)), FileLen(c00 & sn(1)), FileLen(c00 & sn(2)))
For j = 0 To 2
If FileLen(c00 & sn(j)) = Application.Max(st) Then Name c00 & sn(0) As c00 & "L1.csv"
If FileLen(c00 & sn(j)) = Application.Large(st, 2) Then Name c00 & sn(0) As c00 & "L2.csv"
If FileLen(c00 & sn(j)) = Application.Min(st) Then Name c00 & sn(0) As c00 & "L3.csv"
Next
End Sub

Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
22.05.2026 18:27:17
erstmal ungetestet
hab im Moment keine aktuellen csv Dateien mit denen ich testen kann, aber muss das nicht sn(j) statt sn(0) heißen, weil sonst immer die selbe Datei umbenannt wird, egal welche gerade geprüft wird?

Sorry wenn ich mit meinen bescheidenen VBA Kenntnissen da komplett falsch liege, dann nehme ich alles zurück

Gruß
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
22.05.2026 18:27:54
und hallo snb, sorry hab nicht gegrüßt owT
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
snb
23.05.2026 00:00:52
AW: erstmal ungetestet
Du hast völlig recht !!

Sub M_snb()

c00 = "D:\SNB_\"

sn = Split(CreateObject("wscript.shell").Exec("cmd /c dir " & c00 & "*.csv /a/b/o-d").StdOut.ReadAll, vbCrLf)
st = Array(FileLen(c00 & sn(0)), FileLen(c00 & sn(1)), FileLen(c00 & sn(2)))
For j = 0 To 2
If FileLen(c00 & sn(j)) = Application.Max(st) Then Name c00 & sn(j) As c00 & "L1.csv"
If FileLen(c00 & sn(j)) = Application.Large(st, 2) Then Name c00 & sn(j) As c00 & "L2.csv"
If FileLen(c00 & sn(j)) = Application.Min(st) Then Name c00 & sn(j) As c00 & "L3.csv"
Next
End Sub
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Case
24.05.2026 08:58:40
Irgendwo habe...
Moin Christian, :-)

... ich noch eine API-Version. Falls du die mal ausprobieren willst, melde dich. ;-)

Servus
Case
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
24.05.2026 11:07:26
AW: Irgendwo habe...
Hallo Case,

wenn ich ehrlich bin, ich kenne API's bislang nur aus ganz anderen Bereichen wie Schnittstellen zur Datenabfragen auf Internetseiten.
Im Moment kann ich mir nicht vorstellen, was API's mit Dateien umbennen zu tun haben sollen.
Aber wenn du möchtest, kannst du es mir gerne mal schicken, ich lerne ja auch gerne dazu. Ich bitte dich dann aber auch kurz zu erklären was da passiert, da das für mich Neuland ist.

Danke
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Case
24.05.2026 16:03:07
Nun - ich habe mir...
Moin Christian, :-)

… doch überlegt, ob ich das poste. ;-)

Ob du es glaubst oder nicht. Mit API kannst du sogar Kaffee kochen. Früher habe ich die RS232 COM-Schnittstelle abfragen/steuern müssen (heute dann USB). ;-)

Ich höre schon wieder das "Gemecker" - äähh Entschuldigung den "Einwand" - wo ist #If Win64 then…
Selbst ist der Mann(Frau, Es), wenn er (sie, es) 32 Bit will (so viel schaffe ich nicht - da kippe ich vorher um). ;-)

Spaß beiseite (aber Kaffee kochen geht wirklich) - ich höre schon deine Frage: "Ups, das sind aber viele Zeilen Code?" ;-)

Ja - man könnte es kürzen (z. B. mit Private Declare PtrSafe Function EnumDirTreeW Lib "Dbghelp.dll") - aber darauf habe ich keinen Bock. ;-)
Zumal FindFirstFile/FindNextFile auf meiner "Möhre" so schnell läuft, dass ich die Arschbacken nicht zusammenkneifen kann - schon ist es fertig - unter 0,0Irgenwas Sekunden. ;-)

Ich habe in meinen MZ-Tools so viele Beispiele. Ich teste nur noch - geht es - dann ist gut. ;-)

Warum braucht API "so viele" Zeilen gegenüber z. B. WScript.Shell? ;-)

Erklärungsversuch: ;-)

WScript.Shell ist - zumindest bei mir - nicht nur beim ersten Start, da aber besonders - ziemlich langsam. ;-)
WScript.Shell ist bequem, aber nicht kostenlos. ;-)
Beim ersten Start wird erst der COM-Wrapper initialisiert, was spürbar Zeit kostet. ;-)
Direkte API-Aufrufe sind zwar deutlich ausführlicher, umgehen aber diese zusätzliche Schicht. ;-)

Oder noch anders ausgedrückt: ;-)
Die 50 (oder mehr) zusätzlichen Zeilen sind im Prinzip das, was WScript.Shell intern sowieso macht - nur diesmal ohne Warmhalteplatte, COM-Küche und Skript-Butler davor. ;-)
Mit API-Code stehst du praktisch direkt an der "Werkbank von Windows". Du programmierst SEHR Betriebssystemnah. ;-)

So - dann habe ich angefangen den Code zu kommentieren. Darauf hatte ich dann nach 2,3 Zeilen keine Lust mehr. Also habe ich die KI gefragt. Mach mir Kommentare mit Links zu den APIs. ;-)

Ich tendiere ja dazu - keine Leerzeilen, keine Umbrüche. Das ist IMHO unübersichtlich. ;-)

Habe dann zur KI etwa sowas gesagt: ;-)
"Bei mir stellen sich bei Leerzeilen die "Nackenhaare" - ich warte dann immer auf den Schlüsselbund unseres Programmierlehrers (aus den 80gern). Und Umbrüche mache ich grundsätzlich nicht, da ich ja nicht mehr mit einem 15-Zoll-Belinea-Monitor arbeite. Heute arbeitet doch jeder mit 2 oder 3 großen Monitoren - oder mit einem Curved-Monitor, der fast so groß ist, wie der Schreibtisch (wenn man sich nicht gerade den Eichenschreibtisch vom Opa "organisiert" hat)". ;-)

Die KI hat trotzdem mit viel Leerzeilen gearbeitet - und Umbrüchen. ;.)

Du bekommst also erst meine Version: ;-)

Ein Beispiel daraus: ;-)
strRoot = fncGetDLFolder() 'Environ$("USERPROFILE") & "\Downloads"

Privat wirst du ja Downloads nicht umbenennen bzw. es ist nicht über OneDrive geleitet. Dann kannst du mit Environ$("USERPROFILE") & "\Downloads" arbeiten. Schon sind wieder einige Zeilen weg. ;-)

Den habe ich getestet (sind nur ein paar Kommentare drin): ;-)
Option Explicit

' https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-formatmessagew
' Windows-Fehlercode in lesbare Textmeldung umwandeln.
Private Declare PtrSafe Function FormatMessage Lib "kernel32" Alias "FormatMessageW" (ByVal dwFlags As Long, ByVal lpSource As LongPtr, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As LongPtr, ByVal nSize As Long, ByVal Arguments As LongPtr) As Long
'https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-movefileexw
' Verschieben/Umbenennen von Dateien/Verzeichnissen Mit untergeordneten Elementen und Rückrufauswertung.
Private Declare PtrSafe Function MoveFileEx Lib "kernel32" Alias "MoveFileExW" (ByVal lpExistingFileName As LongPtr, ByVal lpNewFileName As LongPtr, ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function SHGetKnownFolderPath Lib "shell32" (ByRef rfid As GUID, ByVal dwFlags As Long, ByVal hToken As LongPtr, ByRef pszPath As LongPtr) As Long
Private Declare PtrSafe Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As LongPtr, lpFindFileData As WIN_FIND_DATA) As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As Long)
Private Declare PtrSafe Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As LongPtr, lpFindFileData As WIN_FIND_DATA) As Long
Private Declare PtrSafe Function FindClose Lib "kernel32" (ByVal hFindFile As LongPtr) As Long
Private Declare PtrSafe Function lstrlenW Lib "kernel32" (ByVal lpString As LongPtr) As Long
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32" (ByVal pv As LongPtr)
Private Declare PtrSafe Function GetLastError Lib "kernel32" () As Long
'https://learn.microsoft.com/de-de/office/vba/language/reference/user-interface-help/type-statement
' Type - Auf Modulebene um um einen benutzerdefinierten Datentyp zu definieren, der ein oder mehrere Elemente enthält.
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName(0 To 259) As Integer
cAlternate(0 To 13) As Integer
End Type
' Was soll passieren, wenn nichts gefunden wird.
Private Const HANDLE_EMPTY As LongPtr = -1
Private Const FILE_ATTRIBUTE_DIRECTORY As Long = &H10
Private Type tTopFile
FilePath As String
FileSize As Double
ft As FILETIME
End Type
Private Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200
Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000
Private Const MOVEFILE_REPLACE_EXISTING As Long = &H1
Private Const strEX As String = ".csv"
Private TopFiles(1 To 3) As tTopFile
Private blnRecursive As Boolean
Public Sub Main_3_CSV()
Dim strTarget As String
Dim strRoot As String
Dim lngCount As Long
Dim lngErr As Long
' Environ$ versagt, wenn Downloads umbenannt oder umgeleitet wurde - deshalb API.
strRoot = fncGetDLFolder() 'Environ$("USERPROFILE") & "\Downloads"
' False = UNTERORDNER WERDEN NICHT DURCHSUCHT
' True = UNTERORDNER WERDEN DURCHSUCHT
blnRecursive = False
' Unbedingt, sonst werden falsche Dateien ausgegeben!
InitTopFiles
SearchFolderRecursive strRoot
Call SortTop3BySize
For lngCount = 1 To 3
If Len(TopFiles(lngCount).FilePath) > 0 Then
strTarget = strRoot & "\L" & lngCount & strEX
If MoveFileEx(StrPtr(TopFiles(lngCount).FilePath), StrPtr(strTarget), MOVEFILE_REPLACE_EXISTING) = 0 Then
lngErr = GetLastError()
MsgBox "Fehler beim Umbenennen:" & vbCrLf & TopFiles(lngCount).FilePath & vbCrLf & "-> " & strTarget & vbCrLf & vbCrLf & GetWinError(lngErr), vbCritical
End If
End If
Next lngCount
End Sub
Private Sub InitTopFiles()
Erase TopFiles
End Sub
Private Sub SortTop3BySize()
Dim lngBubA As Long
Dim lngBubB As Long
Dim tmp As tTopFile
For lngBubA = 1 To 2
For lngBubB = lngBubA + 1 To 3
If TopFiles(lngBubB).FileSize > TopFiles(lngBubA).FileSize Then
tmp = TopFiles(lngBubA)
TopFiles(lngBubA) = TopFiles(lngBubB)
TopFiles(lngBubB) = tmp
End If
Next lngBubB
Next lngBubA
End Sub
Private Sub SearchFolderRecursive(ByVal strFolder As String)
Dim wfd As WIN_FIND_DATA
Dim strSearch As String
Dim lngpFind As LongPtr
Dim strName As String
Dim strFull As String
strSearch = strFolder & "\*"
lngpFind = FindFirstFile(StrPtr(strSearch), wfd)
If lngpFind = HANDLE_EMPTY Then
Debug.Print "Keine Dateien gefunden."
Else
Do
strName = fncPtrToString(wfd.cFileName)
If strName <> "." And strName <> ".." Then
strFull = strFolder & "\" & strName
If (wfd.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) <> 0 Then
If blnRecursive Then SearchFolderRecursive strFull
Else
If LCase$(Right$(strName, 4)) = strEX Then
fncCheckTop3 strFull, wfd
End If
End If
End If
Loop While FindNextFile(lngpFind, wfd)
End If
FindClose lngpFind
End Sub
Private Function fncGetDLFolder() As String
Dim FOLDERID_Downloads As GUID
Dim lngpPath As LongPtr
Dim strPath As String
Dim lngLen As Long
With FOLDERID_Downloads
.Data1 = &H374DE290
.Data2 = &H123F
.Data3 = &H4565
.Data4(0) = &H91
.Data4(1) = &H64
.Data4(2) = &H39
.Data4(3) = &HC4
.Data4(4) = &H92
.Data4(5) = &H5E
.Data4(6) = &H46
.Data4(7) = &H7B
End With
If SHGetKnownFolderPath(FOLDERID_Downloads, 0, 0, lngpPath) = 0 Then
lngLen = lstrlenW(lngpPath)
strPath = String$(lngLen, vbNullChar)
CopyMemory StrPtr(strPath), lngpPath, lngLen * 2
CoTaskMemFree lngpPath
fncGetDLFolder = strPath
End If
End Function
Private Sub fncCheckTop3(ByVal strFile As String, ByRef wfd As WIN_FIND_DATA)
If CompareFileTime(wfd.ftLastWriteTime, TopFiles(1).ft) Then
TopFiles(3) = TopFiles(2)
TopFiles(2) = TopFiles(1)
FillTopFile TopFiles(1), strFile, wfd
ElseIf CompareFileTime(wfd.ftLastWriteTime, TopFiles(2).ft) Then
TopFiles(3) = TopFiles(2)
FillTopFile TopFiles(2), strFile, wfd
ElseIf CompareFileTime(wfd.ftLastWriteTime, TopFiles(3).ft) Then
FillTopFile TopFiles(3), strFile, wfd
End If
End Sub
Private Sub FillTopFile(ByRef t As tTopFile, ByVal strFile As String, ByRef wfd As WIN_FIND_DATA)
t.FilePath = strFile
t.FileSize = CDbl(wfd.nFileSizeHigh) * 4294967296# + wfd.nFileSizeLow
t.ft = wfd.ftLastWriteTime
End Sub
Private Function CompareFileTime(a As FILETIME, b As FILETIME) As Boolean
If a.dwHighDateTime > b.dwHighDateTime Then
CompareFileTime = True
ElseIf a.dwHighDateTime < b.dwHighDateTime Then
CompareFileTime = False
Else
CompareFileTime = (a.dwLowDateTime > b.dwLowDateTime)
End If
End Function
Private Function fncPtrToString(intArr() As Integer) As String
Dim strTemp As String
Dim lngCount As Long
For lngCount = LBound(intArr) To UBound(intArr)
If intArr(lngCount) = 0 Then Exit For
strTemp = strTemp & ChrW$(intArr(lngCount))
Next lngCount
fncPtrToString = strTemp
End Function
Private Function GetWinError(ByVal lngErr As Long) As String
Dim strBuf As String
Dim lngRet As Long
strBuf = String$(512, vbNullChar)
lngRet = FormatMessage( _
FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, 0, lngErr, 0, StrPtr(strBuf), 512, 0)
If lngRet > 0 Then
GetWinError = Left$(strBuf, lngRet)
Else
GetWinError = "Unbekannter Fehlercode: " & lngErr
End If
End Function


Nun der kommentierte Code der KI (den habe ich NICHT getestet): ;-)
Option Explicit

' ============================================================
' Windows API: FormatMessageW
' https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-formatmessagew
' Wandelt einen Windows-Fehlercode in eine lesbare Textmeldung um.
' Wird typischerweise für GetLastError-Auswertung genutzt.
' ============================================================
Private Declare PtrSafe Function FormatMessage Lib "kernel32" Alias "FormatMessageW" ( _
ByVal dwFlags As Long, _
ByVal lpSource As LongPtr, _
ByVal dwMessageId As Long, _
ByVal dwLanguageId As Long, _
ByVal lpBuffer As LongPtr, _
ByVal nSize As Long, _
ByVal Arguments As LongPtr) As Long

' ============================================================
' Windows API: MoveFileExW
' https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-movefileexw
' Verschiebt oder benennt Dateien/Ordner um.
' Unterstützt Flags wie Überschreiben oder verzögertes Verschieben.
' ============================================================
Private Declare PtrSafe Function MoveFileEx Lib "kernel32" Alias "MoveFileExW" ( _
ByVal lpExistingFileName As LongPtr, _
ByVal lpNewFileName As LongPtr, _
ByVal dwFlags As Long) As Long

' ============================================================
' Windows API: SHGetKnownFolderPath
' https://learn.microsoft.com/de-de/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
' Liefert Pfade zu bekannten Windows-Ordnern (z. B. Downloads, Desktop).
' ============================================================
Private Declare PtrSafe Function SHGetKnownFolderPath Lib "shell32" ( _
ByRef rfid As GUID, _
ByVal dwFlags As Long, _
ByVal hToken As LongPtr, _
ByRef pszPath As LongPtr) As Long

' ============================================================
' Windows API: FindFirstFileW
' https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-findfirstfilew
' Startet eine Dateisuche in einem Verzeichnis (*.* Pattern).
' ============================================================
Private Declare PtrSafe Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" ( _
ByVal lpFileName As LongPtr, _
lpFindFileData As WIN_FIND_DATA) As LongPtr

' ============================================================
' Windows API: RtlMoveMemory (CopyMemory)
' https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-rtlmovememory
' Kopiert Speicherblöcke zwischen Pointer-Adressen.
' Wird hier zum Konvertieren von Strings aus API-Pointern genutzt.
' ============================================================
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
ByVal Destination As LongPtr, _
ByVal Source As LongPtr, _
ByVal Length As Long)

' ============================================================
' Windows API: FindNextFileW
' https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-findnextfilew
' Setzt eine gestartete Dateisuche fort (nächster Treffer).
' ============================================================
Private Declare PtrSafe Function FindNextFile Lib "kernel32" Alias "FindNextFileW" ( _
ByVal hFindFile As LongPtr, _
lpFindFileData As WIN_FIND_DATA) As Long

' ============================================================
' Windows API: FindClose
' https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-findclose
' Schließt einen offenen Such-Handle einer Dateisuche.
' ============================================================
Private Declare PtrSafe Function FindClose Lib "kernel32" ( _
ByVal hFindFile As LongPtr) As Long

' ============================================================
' Windows API: lstrlenW
' https://learn.microsoft.com/de-de/windows/win32/api/stringapiset/nf-stringapiset-lstrlenw
' Ermittelt die Länge eines Unicode-Strings (Null-terminiert).
' ============================================================
Private Declare PtrSafe Function lstrlenW Lib "kernel32" ( _
ByVal lpString As LongPtr) As Long

' ============================================================
' Windows API: CoTaskMemFree
' https://learn.microsoft.com/de-de/windows/win32/api/combaseapi/nf-combaseapi-cotaskmemfree
' Gibt Speicher frei, der von COM-APIs reserviert wurde.
' ============================================================
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32" ( _
ByVal pv As LongPtr)

' ============================================================
' Windows API: GetLastError
' https://learn.microsoft.com/de-de/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
' Liefert den letzten Windows-Fehlercode der API-Aufrufe.
' ============================================================
Private Declare PtrSafe Function GetLastError Lib "kernel32" () As Long

' ============================================================
' Type: GUID
' https://learn.microsoft.com/de-de/windows/win32/api/guiddef/ns-guiddef-guid
' Struktur zur Identifikation von Windows-Systemobjekten.
' ============================================================
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type

' ============================================================
' Type: FILETIME
' https://learn.microsoft.com/de-de/windows/win32/api/minwinbase/ns-minwinbase-filetime
' Speichert Zeitstempel in Windows-API-Format (High/Low DWORD).
' ============================================================
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

' ============================================================
' Type: WIN_FIND_DATA
' https://learn.microsoft.com/de-de/windows/win32/api/minwinbase/ns-minwinbase-win_find_dataw
' Enthält Dateiinformationen einer FindFirstFile/FindNextFile-Suche.
' ============================================================
Private Type WIN_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName(0 To 259) As Integer
cAlternate(0 To 13) As Integer
End Type

' ============================================================
' Sentinel-Wert für ungültige Handles (keine Treffer gefunden)
' ============================================================
Private Const HANDLE_EMPTY As LongPtr = -1

' Datei-Attribut: Verzeichnis
Private Const FILE_ATTRIBUTE_DIRECTORY As Long = &H10

' Eigene Struktur für Top-3-Dateien
Private Type tTopFile
FilePath As String
FileSize As Double
ft As FILETIME
End Type

Private Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200
Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000
Private Const MOVEFILE_REPLACE_EXISTING As Long = &H1

Private Const strEX As String = ".csv"

Private TopFiles(1 To 3) As tTopFile
Private blnRecursive As Boolean

Public Sub Main_3_CSV()

Dim strTarget As String
Dim strRoot As String
Dim lngCount As Long
Dim lngErr As Long

' Downloads-Ordner über API (robuster als Environ$)
strRoot = fncGetDLFolder()

' False = keine Unterordner
blnRecursive = False

' Top-3 nach Datum sammeln
InitTopFiles
SearchFolderRecursive strRoot

' =========================================================
' AB HIER: ZWEITER SCHRITT
' Sortierung der 3 neuesten Dateien nach Größe
' =========================================================
Call SortTop3BySize

' =========================================================
' Umbenennen:
' L1 = größte
' L2 = zweitgrößte
' L3 = kleinste
' =========================================================
For lngCount = 1 To 3

If Len(TopFiles(lngCount).FilePath) > 0 Then

strTarget = strRoot & "\L" & lngCount & strEX

If MoveFileEx(StrPtr(TopFiles(lngCount).FilePath), _
StrPtr(strTarget), _
MOVEFILE_REPLACE_EXISTING) = 0 Then

lngErr = GetLastError()

MsgBox "Fehler beim Umbenennen:" & vbCrLf & _
TopFiles(lngCount).FilePath & vbCrLf & "-> " & strTarget & vbCrLf & vbCrLf & _
GetWinError(lngErr), vbCritical
End If

End If

Next lngCount

End Sub

' ============================================================
' Setzt Top-3-Dateiliste zurück
' ============================================================
Private Sub InitTopFiles()
Erase TopFiles
End Sub

' ============================================================
' Sortiert die 3 bereits ermittelten neuesten Dateien
' nach Dateigröße (absteigend)
'
' Ergebnis:
' TopFiles(1) = größte Datei
' TopFiles(2) = zweitgrößte
' TopFiles(3) = kleinste
' ============================================================
Private Sub SortTop3BySize()

Dim i As Long, j As Long
Dim tmp As tTopFile

' Einfacher Bubble-Sort (bei nur 3 Elementen perfekt sinnvoll)
For i = 1 To 2
For j = i + 1 To 3

' Vergleich: Größe absteigend
If TopFiles(j).FileSize > TopFiles(i).FileSize Then

' Swap
tmp = TopFiles(i)
TopFiles(i) = TopFiles(j)
TopFiles(j) = tmp

End If

Next j
Next i

End Sub

' ============================================================
' Rekursive Dateisuche im Ordner
' Sammelt alle CSV-Dateien und bewertet sie nach Datum
' ============================================================
Private Sub SearchFolderRecursive(ByVal strFolder As String)
Dim wfd As WIN_FIND_DATA
Dim strSearch As String
Dim lngpFind As LongPtr
Dim strName As String
Dim strFull As String

strSearch = strFolder & "\*"
lngpFind = FindFirstFile(StrPtr(strSearch), wfd)

If lngpFind = HANDLE_EMPTY Then
Debug.Print "Keine Dateien gefunden."
Else
Do
strName = fncPtrToString(wfd.cFileName)

If strName <> "." And strName <> ".." Then

strFull = strFolder & "\" & strName

If (wfd.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) <> 0 Then
If blnRecursive Then SearchFolderRecursive strFull
Else
If LCase$(Right$(strName, 4)) = strEX Then
fncCheckTop3 strFull, wfd
End If
End If

End If

Loop While FindNextFile(lngpFind, wfd)
End If

FindClose lngpFind
End Sub

' ============================================================
' Ermittelt Downloads-Ordner via Known Folder API
' ============================================================
Private Function fncGetDLFolder() As String
Dim FOLDERID_Downloads As GUID
Dim lngpPath As LongPtr
Dim strPath As String
Dim lngLen As Long

' GUID für Downloads-Ordner
With FOLDERID_Downloads
.Data1 = &H374DE290
.Data2 = &H123F
.Data3 = &H4565
.Data4(0) = &H91
.Data4(1) = &H64
.Data4(2) = &H39
.Data4(3) = &HC4
.Data4(4) = &H92
.Data4(5) = &H5E
.Data4(6) = &H46
.Data4(7) = &H7B
End With

If SHGetKnownFolderPath(FOLDERID_Downloads, 0, 0, lngpPath) = 0 Then
lngLen = lstrlenW(lngpPath)
strPath = String$(lngLen, vbNullChar)

CopyMemory StrPtr(strPath), lngpPath, lngLen * 2
CoTaskMemFree lngpPath

fncGetDLFolder = strPath
End If

End Function

' ============================================================
' Prüft, ob Datei in Top-3 (neueste Dateien) gehört
' ============================================================
Private Sub fncCheckTop3(ByVal strFile As String, ByRef wfd As WIN_FIND_DATA)

If CompareFileTime(wfd.ftLastWriteTime, TopFiles(1).ft) Then
TopFiles(3) = TopFiles(2)
TopFiles(2) = TopFiles(1)
FillTopFile TopFiles(1), strFile, wfd

ElseIf CompareFileTime(wfd.ftLastWriteTime, TopFiles(2).ft) Then
TopFiles(3) = TopFiles(2)
FillTopFile TopFiles(2), strFile, wfd

ElseIf CompareFileTime(wfd.ftLastWriteTime, TopFiles(3).ft) Then
FillTopFile TopFiles(3), strFile, wfd
End If

End Sub

' ============================================================
' Füllt Struktur mit Dateiinformationen
' ============================================================
Private Sub FillTopFile(ByRef t As tTopFile, ByVal strFile As String, ByRef wfd As WIN_FIND_DATA)

t.FilePath = strFile
t.FileSize = CDbl(wfd.nFileSizeHigh) * 4294967296# + wfd.nFileSizeLow
t.ft = wfd.ftLastWriteTime

End Sub

' ============================================================
' Vergleicht zwei FILETIME-Strukturen (neu/alt)
' ============================================================
Private Function CompareFileTime(a As FILETIME, b As FILETIME) As Boolean

If a.dwHighDateTime > b.dwHighDateTime Then
CompareFileTime = True
ElseIf a.dwHighDateTime < b.dwHighDateTime Then
CompareFileTime = False
Else
CompareFileTime = (a.dwLowDateTime > b.dwLowDateTime)
End If

End Function

' ============================================================
' Wandelt Integer-Array (Unicode Pointer) in String um
' ============================================================
Private Function fncPtrToString(intArr() As Integer) As String

Dim strTemp As String
Dim lngCount As Long

For lngCount = LBound(intArr) To UBound(intArr)
If intArr(lngCount) = 0 Then Exit For
strTemp = strTemp & ChrW$(intArr(lngCount))
Next lngCount

fncPtrToString = strTemp
End Function

' ============================================================
' Wandelt Windows-Fehlercode in Textmeldung um
' ============================================================
Private Function GetWinError(ByVal lngErr As Long) As String
Dim strBuf As String
Dim lngRet As Long

strBuf = String$(512, vbNullChar)

lngRet = FormatMessage( _
FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _
0, lngErr, 0, StrPtr(strBuf), 512, 0)

If lngRet > 0 Then
GetWinError = Left$(strBuf, lngRet)
Else
GetWinError = "Unbekannter Fehlercode: " & lngErr
End If

End Function


Zum "spielen" für dich - Christian. ;-)

Hoffe ich habe alles richtig kopiert. ;-)

Servus
Case
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
24.05.2026 17:44:42
AW: Nun - ich habe mir...
Moin Case, :-)

danke dir erstmal für die ausführliche Erklärung und den Code. Jetzt verstehe ich auch besser, was du mit API gemeint hast. Ich hatte bei APIs tatsächlich erstmal nur an Webschnittstellen gedacht. ;-)

Und ja… mein erster Gedanke war tatsächlich: „Ups, das sind aber viele Zeilen Code?“ :-D

Aber nach deiner Erklärung mit COM-Wrapper, WScript.Shell usw. verstehe ich zumindest grob, warum das alles drin steckt und dass du damit deutlich näher direkt an Windows arbeitest.

Ich musste allerdings etwas schmunzeln: Für mein kleines „3 CSV-Dateien umbenennen“-Problem fühlt sich das ein bisschen an wie ein Ferrari-Motor für den Weg zum Bäcker. ;-) Technisch beeindruckend, aber wahrscheinlich deutlich mehr Power als ich momentan überhaupt brauche.

Trotzdem finde ich es spannend zu sehen, wie man sowas direkt über die Windows-API lösen kann. Gerade das mit dem echten Downloads-Ordner statt einfach nur Environ$("USERPROFILE") & "\Downloads" war mir so z. B. gar nicht bewusst.

Den Unterschied mit den „3 neuesten Dateien“ statt „3 größten Dateien insgesamt“ habe ich auch verstanden. Das wäre mir vermutlich erst später aufgefallen. ;-)

Ich werde mir den Code in Ruhe nochmal anschauen und ein bisschen damit spielen. Danke auf jeden Fall für die Mühe und auch für die Erklärungen dazu.

Servus
Christian
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Case
24.05.2026 17:59:34
Also der...
Moin Christian, :-)

... Bäcker ist ca. 500 m Luftlinie von mir weg. Wir machen es so: ;-)

Du schenkst mir einen Ferrari (ich tendiere zum neuesten Modell - also nicht Modellauto) und ich verspreche jeden Tag damit zum Bäcker zu fahren. ;-)

Servus
Case
Forumbeitrag
Excel-Version des Fragestellers:
365 privat
Erfahrungslevel des Fragestellers:
Basiskenntnisse in VBA
Christian
24.05.2026 18:24:31
tut mir leid
fürn Ferrari fehlen mir 500€ (Spaß)