Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Extrem langen Pfad kürzen, Result leer? (https://www.delphipraxis.net/191317-extrem-langen-pfad-kuerzen-result-leer.html)

a.def 2. Jan 2017 18:32


Extrem langen Pfad kürzen, Result leer?
 
Wie würde man korrekt einen zu langen Pfad kürzen?
Ich habe eine Teststruktur die so aussieht:

Code:
D:\0123456789\11111111111111111111111111111111111111111111111111\22222222222222222222222222222222222222222222222222\
33333333333333333333333333333333333333333333333333\44444444444444444444444444444444444444444444444444\
55555555555555555555555555555555555555555555555555\datei.txt
Dieser Pfad ist so lang, dass ich das Verzeichnis 0123456789 selbst nicht mehr mit Windows kopiert bekomme.
Ist hier Schluss mit lustig und Hopfen und Malz verloren oder kann man hier noch was machen um die Datei zu kopieren?

Das Kürzen mit dieser Funktion liefert einen leeren String zurück
Delphi-Quellcode:
function GetShortName(sLongName: string): string;
var
  sShortName:   string;
  nShortNameLen: Integer;
begin
  SetLength(sShortName, MAX_PATH);
  nShortNameLen := GetShortPathName(PChar(sLongName), PChar(sShortName), MAX_PATH - 1);
  if (0 = nShortNameLen) then
  begin
    // handle errors...
  end;
  SetLength(sShortName, nShortNameLen);
  Result := sShortName;
end;

nahpets 2. Jan 2017 18:45

AW: Extrem langen Pfad kürzen, Result leer?
 
Delphi müsste eigentlich ExtractShortPathName kennen (SysUtils).

Delphi-Quellcode:
ExtractShortPathName('C:\Program Files\MyCompany\MyApp\MyApp.exe')
sollte "C:\Progra~1\MyComp~1\MyApp\MyApp.exe" liefern.

Aus deinem Beispiel könnte damit dann sowas werden:

D:\012345~1\111111~1\222222~1\333333~1\444444~1\55 5555~1\datei.txt

Dalai 2. Jan 2017 18:47

AW: Extrem langen Pfad kürzen, Result leer?
 
Der Pfad ist mit 278 Zeichen länger als MAX_PATH. Die allermeisten der API-Funktionen dürften damit ihre Probleme haben. Lösung: Syntax benutzen, die längere Pfade erlaubt:
Code:
\\?\D:\0123456789\...
IIRC wird aber diese Syntax nicht von allen API-Funktionen unterstützt.

Grüße
Dalai

EWeiss 2. Jan 2017 18:50

AW: Extrem langen Pfad kürzen, Result leer?
 
Keine Ahnung ob das relevant für Win7 ist. (Falls du es benutzt)
Check mal in der Registry ob 8dot3NameCreation aktiviert bzw. deaktiviert ist.

http://www.msfn.org/board/topic/1352...comment=986576

gruss

a.def 2. Jan 2017 19:05

AW: Extrem langen Pfad kürzen, Result leer?
 
1) Ist aktiviert.
2) \\?\ hat kein Auswirkung auf Pfade > MAX_PATH
3) ExtractShortPathName ebenfalls ein leerer String

So wie es aussieht, gibt es hier keine Lösung. Denn Windows selber kann das Verzeichnis sogar nicht verarbeiten.

Frage: gilt MAX_PATH nur für Dateinamen oder für den kompletten Pfad?

jobo 2. Jan 2017 19:33

AW: Extrem langen Pfad kürzen, Result leer?
 
Ich hatte neulich mit einem Backup Probleme wegen zu langer Pfade.
Es gibt dafür naheliegende und absurde Lösungen/Vorschläge.
Eine Möglichkeit, die bei mir prima funktioniert hat ist die Nutzung/ Erzeugung eines Links. (So wie man sie von Unixen kennt, ich glaub MS nennt das junction)
per CMD:
- Link auf irgendeinen mittleren Teil des Pfades anlegen
- Löschen / Ändern im Link übrig bleibenden Pfadnamen
- Link löschen

Das kann man iterativ machen, bis ein "normaler" Zugriff funktioniert. Wahrscheinlich sogar intelligenter, wenn man ein bisschen Längenbestimmung macht.

Es ist allerdings nicht in jeder OS Version verfügbar, bis XP glaub ich, erst ab Win7, bin nicht ganz sicher.
Ggf. kannst Du das programmatisch implementieren, wenn Du mit der OS Version auf der sicheren Seite bist.

himitsu 2. Jan 2017 19:34

AW: Extrem langen Pfad kürzen, Result leer?
 
MAX_PATH ist der komplette "Pfad", inkl. Datei-/Verteichnisname, Verzeichnisse, Laufwerk und der letzten #0.

a.def 2. Jan 2017 19:38

AW: Extrem langen Pfad kürzen, Result leer?
 
Kann man dementsprechend abschließend festhalten, dass wenn die Länge Pfad sPathXYZ > MAX_PATH ist, man ihn am besten aus der Verarbeitung raushält um Fehler zu vermeiden?

Aviator 2. Jan 2017 20:00

AW: Extrem langen Pfad kürzen, Result leer?
 
Also direkt über die Win API kann man bis Windows 8.1 nur Pfade mit der Länge von MAX_PATH kopieren. Es gab aber die bereits erwähnte Alternative mit \\?\ um Pfade zu kopieren die länger sind als MAX_PATH. Probiert habe ich das selbst nie und kann daher auch keine Lösung anbieten. Ab Windows 10 (ab einem speziellen Build soweit ich weiß) wurden die WinAPI Funktionen angepasst sodass sie Pfade bis 2^15 Zeichen verarbeiten können.

Dalai 2. Jan 2017 20:20

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Zitat von Aviator (Beitrag 1357824)
Also direkt über die Win API kann man bis Windows 8.1 nur Pfade mit der Länge von MAX_PATH kopieren. Es gab aber die bereits erwähnte Alternative mit \\?\ um Pfade zu kopieren die länger sind als MAX_PATH.

... was auch über die WinAPI erfolgt - insofern widerspricht der zweite Satz dem ersten :).

Probiert habe ich es selbst auch nie, aber da ich weiß, dass Total Commander mit Pfaden länger 256 Zeichen umgehen kann (geht IIRC bis 1024) und der natürlich mit der WinAPI arbeitet, kann ich mit Sicherheit sagen, dass es funktioniert. Nur mal ein Beispiel: MSDN-Library durchsuchenCopyFileEx:
Zitat:

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.
Es muss also die Unicode-Variante der Funktion gerufen werden, der Prefix muss vorhanden sein, und natürlich darf man den String nicht auf MAX_PATH kürzen. Und wie ich schon sagte können möglicherweise nicht alle API-Funktionen mit den überlangen Pfaden umgehen; LoadImage, LoadIcon fallen mir da spontan ein.

Grüße
Dalai

Aviator 2. Jan 2017 20:23

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Zitat von Dalai (Beitrag 1357830)
... was auch über die WinAPI erfolgt - insofern widerspricht der zweite Satz dem ersten :).

Ja ok. Wie gesagt ich habe es nie probiert und wusste es daher nicht. Aber logisch wäre es schon. Nur muss man dann scheinbar spezielle Funktionen aufrufen. Sind das alle mit "Ex" am Schluss?

Dalai 2. Jan 2017 20:29

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Zitat von Aviator (Beitrag 1357831)
Nur muss man dann scheinbar spezielle Funktionen aufrufen.

Nicht spezielle Funktionen, nur der Pfad im entsprechenden Parameter ist anders.

Zitat:

Sind das alle mit "Ex" am Schluss?
Nicht nur. Für MSDN-Library durchsuchenGetShortPathName schreibt MS denselben Satz wie für CopyFileEx, diese Funktion soll also auch damit umgehen können.

Grüße
Dalai

HolgerX 2. Jan 2017 20:36

AW: Extrem langen Pfad kürzen, Result leer?
 
Hmm..

Damit geht es:

Delphi-Quellcode:
// nur wenn NtfsDisable8dot3NameCreation=0
function GetShortName(sLongName: WideString): WideString;
var
  sShortName: WideString;
  nShortNameLen: Integer;
begin
  sShortName := '';
  nShortNameLen := 0;
  nShortNameLen := GetShortPathNameW(PWideChar(sLongName), nil, nShortNameLen);
  if nShortNameLen > 0 then begin
    SetLength(sShortName, nShortNameLen);
    nShortNameLen := GetShortPathNameW(PWideChar(sLongName), PWideChar(sShortName), nShortNameLen);
    if (nShortNameLen = 0) then
      raise Exception.Create(SysErrorMessage(GetLastError));
    Result := sShortName;
  end else begin
    raise Exception.Create(SysErrorMessage(GetLastError));
  end;
  Result := sShortName;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  s : Widestring;
begin
  s := '\\?\D:\0123456789\11111111111111111111111111111111111111111111111111';
  s := s + '\22222222222222222222222222222222222222222222222222';
  s := s + '\33333333333333333333333333333333333333333333333333';
  s := s + '\44444444444444444444444444444444444444444444444444';
  s := s + '\55555555555555555555555555555\Datei.txt';

  Edit1.Text := GetShortName(s); // \\?\D:\012345~1\111111~1\222222~1\333333~1\444444~1\555555~1\Datei.txt
end;
Selbst unter Delphi 6 ;)

Bedingt aber, das NtfsDisable8dot3NameCreation=0 gesetzt ist, eventuell VOR dem Erzeugen der Verzeichnisse und der Datei.

a.def 2. Jan 2017 20:43

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Zitat von HolgerX (Beitrag 1357834)
Bedingt aber, das NtfsDisable8dot3NameCreation=0 gesetzt ist, eventuell VOR dem Erzeugen der Verzeichnisse und der Datei.

Was dann wieder das Problem birgt, dass nicht jeder dieselben Einstellungen hat.

EWeiss 2. Jan 2017 20:47

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Bedingt aber, das NtfsDisable8dot3NameCreation=0 gesetzt ist, eventuell VOR dem Erzeugen der Verzeichnisse und der Datei.
Fein das wenigstens einer mit meinen Informationen gearbeitet hat.
Zitat:

Was dann wieder das Problem birgt, dass nicht jeder dieselben Einstellungen hat.
Wo ist das Problem diese zu setzen oder zu deaktivieren.
Du sagst ja selbst..
Zitat:

dass wenn die Länge Pfad sPathXYZ > MAX_PATH ist, man ihn am besten aus der Verarbeitung raushält um Fehler zu vermeiden?
Was hindert dich daran abhängig von der länge des strings die variable in der registry zu ändern?


gruss

HolgerX 2. Jan 2017 20:55

AW: Extrem langen Pfad kürzen, Result leer?
 
Hmm...

Tja, wo seitens NTFS keine 8.3 Namen erzeugt/hinterlegt wurden, da kann mann auch keinen kurzen Namen bekommen...

Deshalb sollte die Funktion dann immer den original Namen, also ungekürzt liefern, wenn dieser nicht vorhanden ist.

Denn der kurze Name ist im NTFS hinterlegt und wird nicht neu erzeugt, wenn man GetShortPathName verwendet.

Viele APIs ermöglichen das Verwenden in der W-Version von '\\?\', somit kann da auch gelöscht und kopiert werden.

Nur der Windows-Explorer kann das nicht ;)

Dalai 2. Jan 2017 21:06

AW: Extrem langen Pfad kürzen, Result leer?
 
Zitat:

Zitat von HolgerX (Beitrag 1357834)
Bedingt aber, das NtfsDisable8dot3NameCreation=0 gesetzt ist [...]

Da das Abspeichern/Erzeugen kurzer Dateinamen Standardeinstellung ist (d.h. man muss nur aktiv werden, wenn man das nicht will), sehe ich da kein wirkliches Problem. Es mag Gründe für das Abschalten kurzer Namen geben, aber ich denke, die meisten Leute, bei denen das der Fall ist, haben mit irgendeinem Tuning-Tool und/oder ohne ausreichendes Wissen rumgefummelt.

Grüße
Dalai

himitsu 3. Jan 2017 01:10

AW: Extrem langen Pfad kürzen, Result leer?
 
NtfsDisable8dot3NameCreation bedeutet "nur", dass nicht gleich zu Beginn auch immer der 8.3-Dateiname erzeugt wird. (hatte ich so mal irgendwo gelesen, aber kann auch nur Aberglaube sein)
Wenn es nötig ist, sollte Windows diesen Pfadnamen dennoch erstellen.
Allerdings kann es sein dass MSDN-Library durchsuchenGetShortPathName nur bestehende Namen abfragt und bei Nichtexistenz die Arbeit einfach abbricht.

Man könnte es explizit mit der ANSI-Version dieser API versuchen.
Bei ANSI greifen in vielen APIs oftmals Sicherheitsmaßnamen (abwärtskompatibilität), wo dann dennoch diese kurzen "DOS"-Namen generiert werden.


Und ja, auch der Explorer kann mit überlangen Pfaden umgehen, aber wie bei den meisten APIs nur für relative Pfade oder bei Verwendung von UNC.
Ebenso verstehen viele (nicht alle) überlange Pfade nur via UNC. Gilt aber oftmals nicht für APIs, die Pfadnamen "manipulieren" und das in "statischen" Puffern erledigen, wie eventuell bei GetShortPathName.

Luckie 3. Jan 2017 01:16

AW: Extrem langen Pfad kürzen, Result leer?
 
Also, ich verstehe das so. Wenn aktiviert, speichert/erzeugt Windows neben bei noch die kurzen Dateinamen. Wenn deaktiviert hat man Pech, weil Windows nur die langen Dateinamen/Pfade kennt. Ergo sum. Wenn vorher deaktiviert, hat der Threadersteller keine Chance auf die kurzen Dateinamen/Pfade zu zugreifen, weil sie nicht esxistieren.

HolgerX 3. Jan 2017 05:33

AW: Extrem langen Pfad kürzen, Result leer?
 
Hmm..

Also, der Default-Wert von NtfsDisable8dot3NameCreation ist übrigens '2' und nicht '0'.
Früher gab es nur 0 und 1 und seit zumindestens Windows7 (glaube ich) gibt es noch 2 und 3.

Zitat:

Value and Meaning

0 NTFS creates short file names. This setting enables applications that cannot process long file names and computers that use differentcode pages to find the files.

1 NTFS does not create short file names. Although this setting increases file performance, applications that cannot process long file names, and computers that use different code pages, might not be able to find the files.

2 NTFS sets the 8.3 naming convention creation on a per volume basis.

3 NTFS disables 8dot3 name creation on all volumes except the system volume.

Unter meinem Win8.1 stand es auf 2 und die kurzen Namen wurden nicht generiert.
Erst nach dem Umstellen (und Neubooten) wurden auch die Kurzen Namen bei Neuanlage des Verzeichnisses erzeugt.

Die ANSI-Version von GetShortPathName kann übrigens auch keine ShortNames bringen, wenn im File-System keine vorhanden sind.
Auch ist die ANSI-Version auf MAX_PATH begrenzt und nur die Wide-Version kann die 32K langen FileNames.

Somit sollte sich der TE nicht darauf verlassen, dass er die Shotnames auf anderen Systemen bekommt.

a.def 3. Jan 2017 10:09

AW: Extrem langen Pfad kürzen, Result leer?
 
Nach einigen Tests habe ich jetzt herausgefunden, dass Windows intern wohl selbst schon den kurzen Pfad sucht, wenn man \\?\ als Prefix verwendet.
Gestern hat das nicht funktioniert.

Situaton gestern war, dass NtfsDisable8dot3NameCreation aus irgendeinem Grund nicht auf 2 stand.

Folgende Funktion klappt einwandfrei (auch ohne getShortName)
Delphi-Quellcode:
function getUNCPath(aPath: string): string;
var
 bIsUNC: Boolean;
begin
 aPath := ExpandFileName(aPath);

 bIsUNC := Copy(aPath, 1, 2) = '\\';
 if not bIsUNC then
  aPath := '\\?\' + aPath;

 Result := aPath;
end;

Ansonsten sieht mein Wirr-Warr jetzt so aus
Delphi-Quellcode:
function getShortName(sLongName: WideString; bReturnLongIfNotFound: Boolean = False): WideString;
var
 sShortName: WideString;
 nShortNameLen: Integer;
begin
 Result := '';

 // Prüfung auf MAX_PATH. Wenn KLEINER MAX_PATH, gebe sLongName zurück,
 // da es sonst u.U. Zeit kosten kann, wenn die Datei sLongName nicht existiert.
 if Length(sLongName) > MAX_PATH then
  begin
   sShortName := '';
   nShortNameLen := 0;
   nShortNameLen := GetShortPathNameW(PWideChar(sLongName), nil, nShortNameLen);
   if nShortNameLen > 0 then
    begin
     SetLength(sShortName, nShortNameLen);
     nShortNameLen := GetShortPathNameW(PWideChar(sLongName), PWideChar(sShortName), nShortNameLen);

     if nShortNameLen > 0 then
      Result := sShortName;
    end
   else
    begin
    end;
  end
 else
  Result := sLongName;

 // Sollte Result aus irgendeinem Grund leer sein, gebe sLongName zurück (falls gewollt)
 if (Result = '') and bReturnLongIfNotFound then
  Result := sLongName
 else
  Result := sShortName;
end;

// sPath := irgendetwas, das länger als MAX_PATH ist ...
sPath := getUNCPath(sPath); // funktioniert
sPath := getShortName(getUNCPath(sPath), True); // funktioniert

// ohne eine der beiden Funktionen, funktioniert Weiteres (natürlich) nicht


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:46 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz