![]() |
SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Hallo,
ich knabbere grade an folgendem Problem: Ich kopiere diverse Dateien mittels SHFileOperation. Jetzt bekomme ich jedoch bei einigen Dateien mit einem sehr langen Dateinamen die Fehlermeldung, das der Dateiname oder die Erweiterung zu lang sei. Kann man solche Dateien trotzdem irgendwie kopieren? Die Funktion zum Kopieren der Dateien sieht wie folgt aus:
Delphi-Quellcode:
function ShellFileCopy(const aSource, aDest: string): Integer;
var SH: TSHFileOpStruct; begin ZeroMemory(@SH, SizeOf(SH)); try with SH do begin Wnd := 0; wFunc := FO_COPY; pFrom := PChar(aSource + #0); pTo := PChar(ExtractFilePath(aDest) + #0); fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR or FOF_SILENT; end; Result := SHFileOperation(SH); finally ZeroMemory(@SH, SizeOf(SH)); end; end; |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Hilft evtl
Delphi-Quellcode:
:?:
function LongFileNameToShortFileName(const LongFileName: string): string; inline;
begin Result := ''; SetLength(Result, GetShortPathName(PAnsiChar(LongFileName), nil, 0)); if Length(Result) > 0 then begin GetShortPathName(PAnsiChar(LongFileName), PAnsiChar(Result), Length(Result)); SetLength(Result, Length(Result)-1); end; end; Ein Versuch wär´s wert :) |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Um Dateinamen/Pfade nutzen zu können, welche länger als MAX_PATH sind, kannst du diese vorher ins UNC-Format übersetzen und schon sollte/könnte es gehn.
Im einfachsten Fall einfach ein '\\.\' vor jeden Pfad, also z.B. '\\.\C:\Verzeich.nis\Dat.ei' . |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Und dann gab es doch noch den "Supertrick" von Microsoft, dass man dem Pfad den Prefix "\\?\" vorneanstellen kann und dann Pfadlängen bis 32kB haben darf.
PS: "//./" hat laut Microsoft eine andere Bedeutung. |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
@mleyen: Ohne es getestet zu haben, mal ganz dumm gefragt: Der ursprüngliche Dateiname bleibt aber erhalten oder bekommt die Kopie den verkürzten Namen. Ich frage deshalb, weil das Problem bei einem Kunden aufgetreten ist und der sich bedanken wird, wenn unser Programm die Dateinamen seiner Dokumente "zerschießt" 8-)
@himitsu: Also im Prinzip so (Pseudo-Code)
Delphi-Quellcode:
if Length(sDateiname) > MAX_PATH then
sDateiname := '\\.\' + sDateiname |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Im Prinzip ja ... oder eben
Delphi-Quellcode:
:gruebel:
sDateiname := '\\?\' + sDateiname
PS: Wenn du nur Lesend auf Dateien zugreifen mußt oder wenn der Dateiname noch Kurz und nur der gesamte Pfad zu lang ist, dann kannst du auch die alten Kurznamen verwenden, welche oftmals noch vorhanden sind.
Code:
C:\Meine Programme\ein gaaaaaaaaaaaaaaaaaaaaaaaaaaanz lange Pfad\die liebe Datei.txt
C:\MEINEP~1\EINGAA~7\die liebe Datei.txt C:\MEINEP~1\EINGAA~7\DIELIE~8.TXT @shmia: war mir nicht ganz sicher, darum hatte ich nochmal schnell nachgesehn ... Wiki meinte Folgendes und ich dachte mir so der Punkt war passender :stupid: Zitat:
Delphi-Quellcode:
,
\\.\
Delphi-Quellcode:
,
\\?\
Delphi-Quellcode:
oder ... ist halt nicht so einfach :oops:
\??\
PS: 64 KB = 32k Unicode-Zeichen |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Auf die nicht existierende aDest-Datei würd ich es jetzt auch nicht anwenden.
Ansonsten kann man afaik immer den langen Dateinamen wieder rausbekommen. Aber der '\\?\'-Trick scheint ja die offizielle-ordentliche Variante zu sein. |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Okay, mit dieser Funktion sollte dann also das Kopieren von Dateien mit sehr langem Dateinamen klappen:
Delphi-Quellcode:
Oder ist mir da irgend ein Denkfehler unterlaufen? :gruebel:
function ShellFileCopy(const aSource, aDest: string): Integer;
var SH: TSHFileOpStructW; sSource, sDest: WideString; begin ZeroMemory(@SH, SizeOf(SH)); sSource := aSource; sDest := ExtractFilePath(aDest); if (Length(sSource) > MAX_PATH) then if (Copy(sSource, 1, 2) = '\\') then sSource := '\\?\UNC' + sSource else sSource := '\\?\' + sSource; if (Length(sDest) > MAX_PATH) then if (Copy(sDest, 1, 2) = '\\') then sDest := '\\?\UNC' + sDest else sDest := '\\?\' + sDest; try with SH do begin Wnd := 0; wFunc := FO_COPY; pFrom := PWideChar(sSource + #0); pTo := PWideChar(sDest + #0); fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR or FOF_SILENT; end; Result := SHFileOperationW(SH); finally ZeroMemory(@SH, SizeOf(SH)); end; end; |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Delphi-Quellcode:
?
if (Length(sXYZ) >= MAX_PATH) and not StartsText('\\?\', sXYZ) then
Sonst würdest du es auch anhängen, wenn es schon da ist. Und vergißt bitte nicht, daß in MAX_PATH die abschließende #0 mitgezählt wird (drum >= ). Und sicherheitshalber noch ein
Delphi-Quellcode:
davor.
sXYZ := ExpandFileName(sXYZ);
|
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Zwei Probleme:
1: Der problematische Dateiname ist "nur" 250 Zeichen lang, MAX_PATH steht aber auf 260 :wall: 2: Wenn ich pauschal den Pfaden ein "\\?\" voranstelle, liefert SHFileOperation den Fehler 124 (Die Ebene des Systemaufrufs ist falsch) zurück :shock: |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Zitat:
Also, der gesamte Pfad (Datei + Verzeichnis), ohne Laufwerk ( C:\ ) darf nicht länger als 256 Zeichen sein (inkl. der #0 oder war's ohne dieser :gruebel: ) , zumindestens ist das bei den standardmäßig vorhandenen FAT- und NTFS-Treibern so. 2. Und was ist mit einem
Delphi-Quellcode:
?
'\\.\'
|
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Zitat:
Zitat:
Oder kann es vielleicht sein, das SHFileOperation mit diesen Präfixen nicht klar kommt? |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Okay, so scheint es zu funktionieren:
Delphi-Quellcode:
function ShellFileCopy(const aSource, aDest: string): Integer;
var SH: TSHFileOpStructW; sSource, sDest: WideString; const sPrefix: WideString = '\\?\'; sUNCNewPrefix: WideString = '\\?\UNC'; sUNCPrefix: WideString = '\\'; begin if not StartsText(sUNCPrefix, aSource) then sSource := ExpandFileName(aSource); if not StartsText(sUNCPrefix, aDest) then //sDest := ExtractFilePath(ExpandFileName(aDest)); sDest := ExpandFileName(aDest); if (Length(sSource) >= MAX_PATH) and not StartsText(sPrefix, sSource) then if StartsText(sUNCPrefix, sSource) then sSource := sUNCNewPrefix + sSource else sSource := sPrefix + sSource; if (Length(sDest) >= MAX_PATH) and not StartsText(sPrefix, sDest) then if StartsText(sUNCPrefix, sDest) then sDest := sUNCNewPrefix + sDest else sDest := sPrefix + sDest; ZeroMemory(@SH, SizeOf(SH)); try with SH do begin Wnd := 0; wFunc := FO_COPY; pFrom := PWideChar(sSource + #0); pTo := PWideChar(sDest + #0); fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR or FOF_SILENT; end; Result := SHFileOperationW(SH); finally ZeroMemory(@SH, SizeOf(SH)); end; end; |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Mit Freude habe ich HeikoAdams Code übernommen, da er mir sehr gut zupass kam.
Bei der Verwendung stellt sich dann aber heraus, dass er ein paar Fallstricke enthält. So berücksichtigt der Code leider nicht den Fall, dass der Anwender (so wie ich) von sich aus bereits ein '\\?\' vor die Dateinamen setzt. In einem solchen Fall enthalten sQuelle und sZiel nur leere Strings, aber leider liefert die Funktion trotzdem (!) eine 0 als Zeichen für eine korrekte Ausführung. Und, wie schon bemerkt, darf man leider auch nicht einfach ein '\\?\' vor alle Dateinamen setzen. Bei Dateinamen >= MAX_PATH muss es stehen, bei kürzeren darf es nicht stehen. Das muss man nicht verstehen, vor allem nicht, da Microsoft ![]() ![]() Ich habe daher den Code etwas umgegraben. Für mich funktioniert er; das tat er bei HeikoAdams aber auch, warten wir also wieder drei Jahre. :wink: PS: Ich ziehe den Code zurück, siehe Beitrag unten. |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Scheint das Thema zu sein:
![]() |
AW: SHFileOperation: Wie Dateien mit sehr langem Dateinamen kopieren?
Ich habe meine Codeanpassung wieder zurückgezogen, da der Code in seltenen, aber in der Praxis vorkommenden Fällen nicht funktioniert.
Hierbei habe ich vor allem auch ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz