Announcement

Collapse
No announcement yet.

MkDir mit extrem langen Pfadnamen funktioniert nicht

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • MkDir mit extrem langen Pfadnamen funktioniert nicht

    Hallo zusammen!

    Ich versuche hier mittels eines eigenen Delphi-Programmes eine vorhandenen Verzeichnisbaum zu bearbeiten.
    Dieser Verzeichnisbaum hat nur leider die unangenehme Eigenschaft, sehr tief geschachtelt zu sein. Dadurch ergeben sich Pfadnamen, die deutlich länger als 260 Zeichen sind. Mit solchen Längen habe alle möglichen Programme Probleme. Nur die MS-eigenen nicht. Insbesondere der Windows-Explorer und das Office-Paket (zumindest ab 2000) arbeiten damit einwandfrei.
    Deshalb hat wohl auch in all den Jahren niemand hier gemerkt, dass diese Struktur etwas suboptimal ist...

    Mir ist klar, das NTFS grundsätzlich die Pfadlänge zunächst auf MAX_PATH (=260) Zeichen begrenzt und nur über die Unicode-Bibliotheken mehr kann.

    Ich habe mich nun schon durch alle möglichen Dateifunktionen gewühlt.
    Mit CopyFileEx (Unicodeversion mittels '\\?\') kann ich z.B. auch kopieren. Nur muß das Zielverzeichnis dann schon existieren.
    Leider kann MkDir solche Verzeichnisse nicht anlegen.

    Mit ShFileOperations komme ich auch nicht weiter. Trotz ausreichend groß dimensionierter Puffer (Beispiel von A.Kosch hier aus dem Forum kopiert), tritt ein Fehler auf und es passiert nichts weiter.

    Die Aussage, ShFileOperations würde von Windows selbst verwendet, kann so nicht stimmen, da der Explorer und Office wunderbar arbeiten, mein Programm (und andere) nicht.

    Gibt es noch irgendwo eine zugängliche Funktion? Kann man den Windows-Explorer vielleicht irgendwie ein ein Delphi-2007-Programm einbinden?

    verzweifelt,
    nextX

  • #2
    Du mußt dich "durchhangeln" (Sprich: Aktuellen Pfad der Anwendung passend setzen) um dann nur mit kürzeren relativen Pfaden arbeiten zu können um jeweils nur (relative) Pfade zu haben die < 260 Zeichen sind

    Comment


    • #3
      moin,

      mühsam, aber funzt immer: pfade zerhacken und jeden schritt einzeln

      (wie zu DOS Zeiten ;-))

      gruss, bernhard

      Comment


      • #4
        Hallo.

        Statt z.B. "C:\dokumente und einstellungen\" zu schreiben, kann man es auch mit "c:\doku*" versuchen (zumindest auf der Kommandozeile). Der Verzeichnisname sollte aber schon eindeutig sein.

        Gruss
        MfG
        Cheat-Sheets for Developers / Programming Quotes

        Comment


        • #5
          Danke für den Tipp, aber leider funktioniert das nicht...

          Ich habe mal eine kleine Testroutine zur Verdeutlichung gebaut. Da wird versucht, einen Testbaum mit über 300 Zeichen Pfadlänge aufzubauen.
          Beim Versuch an 253 Zeichen noch 10 dran zu bekommen, knallt es mit Fehler 206 - Pfad zu lang.

          Abgesehen davon hätte ich jetzt noch keine rechte Idee, wie ich aus so einem langen Pfad von "ganz unten" in einen anderen langen Pfad "ganz unten" kopieren soll. Aber das kommt später...


          Code:
          procedure TForm1.BitBtn1Click(Sender: TObject);
          var
            i : integer;
            d : string;      // Teilpfad
            Pfad : string;   // gesammter bisher bearbeiteter Pfad
          begin
            Pfad := 'C:\TestMkDir\';  // hier wird gestartet
          
            try
              MkDir(Pfad);
              ChDir(Pfad);
          
              d := '123456789\';
              for i := 1 to 30 do begin
                Pfad := Pfad + d;
          
                MkDir(d);
                ChDir(d);
              end;
          
            except
              On e : Exception do begin
               Application.MessageBox(pansichar(e.Message),'FEHLER', MB_OK);
          
              end;
            end;
          
            Application.MessageBox(pansichar(Pfad),
                                pansiChar('Pfad angelegt: ' + sysutils.IntToStr(length(Pfad))),
                                MB_OK);
          
          end;

          Comment


          • #6
            Hallo,

            Für Deinen Gesamtpfad kannst Du Dir ja einen Array aufbauen und für jeden
            Unterpfad einen neuen Index nehmen.
            Damit hast Du auch gleich das Problem des späteren Durchhangelns total vereinfacht. Du mußt Dir nur noch den maximalen Index merken :

            procedure TForm1.BitBtn1Click(Sender: TObject);
            var
            i : integer;
            d : string; // Teilpfad

            Pfad : array[0..30] of string; // gesamter bisher bearbeiteter Pfad

            begin
            Pfad[0] := 'C:\TestMkDir'; // hier wird gestartet

            try
            MkDir(Pfad[0]);
            ChDir(Pfad[0]);

            d := '123456789';
            for i := 1 to 30 do begin

            Pfad [i]:= d;
            MkDir(d);
            ChDir(d);
            end;

            except
            On e : Exception do begin
            Application.MessageBox(pansichar(e.Message),'FEHLE R', MB_OK);
            end;
            end;

            Application.MessageBox(pansichar(Pfad),
            pansiChar('Pfad angelegt: ' + sysutils.IntToStr(length(Pfad))),
            MB_OK);

            end;

            Die einzelnen Unterpfade werden ja wohl nicht länger als 256 Zeichen sein.

            Gruß frauwue
            docendo discimus

            Comment


            • #7
              Originally posted by frauwue View Post
              Hallo,

              Für Deinen Gesamtpfad kannst Du Dir ja einen Array aufbauen und für jeden
              Unterpfad einen neuen Index nehmen.
              Damit hast Du auch gleich das Problem des späteren Durchhangelns total vereinfacht.
              Das Durchhangeln durch den Pfad ist nicht mein Problem.

              Die einzelnen Unterpfade werden ja wohl nicht länger als 256 Zeichen sein.
              Nicht die Teilpfade, sondern der gesamte Pfad. Vom Laufwerksbuchstaben bis zum eigentlichen Dateinamen ist der Pfad teilweise sehr lang.

              Mir ist zwar nicht ganz klar, wie die Anwender es geschafft haben, solche Monstren anzulegen, ohne auf Fehlermeldungen zu laufen, aber die Verzeichnisse und Dateien sind definitiv da. Nun muss ich damit leben, denn ein umorganisieren ist enorm zeitaufwändig. Und da das System sich ja scheinbar nicht weigert, ist vorprogrammiert, dass in Zukunft wieder solche Pfade entstehen.

              Beispiel:
              Früher hätte man ein Verzeichnis "KK-HH" genannt.
              Heute nennt man es "Daten für das Kernkraftwerk in Hamburg-Busenbüttel"

              Wenn man das ein paar mal untereinander schachtelt, kommen halt solche Pfade zustande.

              Das es irgendwie gehen muss, zeigt die Funktion CopyFileEx, die in der Unicodeversion durchaus mit längern Pfadnamen umgehen kann. Lt. Hilfe bis zu ca. 32000 Zeichen.

              Sowas suche ich nun halt auch für MkDir.

              Comment


              • #8
                Hallo NextX,

                ich habe Deine Problematik durchaus verstanden. Mit Durchhangeln könntest Du aber alles erschlagen auch das Kopieren. Du gehst zuerst bis zum Quellpfad, kopierst Deine Datei in einen kurzen Hilfspfad. Dann hangelst Du Dich zum Zielpfad durch und kopierst die Datei aus dem Hilfspfad dorthin.

                Gruß frauwue
                docendo discimus

                Comment


                • #9
                  Wenn Du meinen Beispielcode betrachtest (oder mal in Delphi ausführst, einfach einen Button auf ein leeres Formular ziehen), dann wirst Du sehen, dass dort nicht mit dem vollständigen Pfad, sondern nur jeweils mit dem aktuellen Verzeichnisnamen (10 Zeichen lang) gearbeitet wird.

                  Der volle Pfad erscheint nur in der Fehlermeldung.

                  Bei der Ausführung der Routine kommt es nach 24 Durchläufen (= 253 Zeichen Pfadlänge) zum Abbruch / Exception mit Fehler 206 (Pfad zu lang)
                  Das ich über eine Zwischenstation kopieren könnte, ist mir klar.

                  Nur muss zu allererst ja mal das Zielverzeichnis existieren.

                  Dummerweise muss bei der Kopieraktion die Verzeichnisstruktur der Quelle erhalten bleiben. Die Quelle zu lesen, klappt noch. Aber das Zielverzeichnis erstellen nicht. Das Zielverzeichnis ist mein einziges Problem.

                  Gruß,
                  nextX

                  Comment


                  • #10
                    Hallo nextX,

                    ich habs jetzt probiert. Ist bei mir genauso. Dann habe ich mal versucht im Windows-Explorer noch ein zusätzliches Verzeichnis zu erzeugen. Dann bekomme ich direkt unter Windows die Meldung:

                    Der Ordner "Neuer Ordner" konnte nicht erstellt werden.
                    Der Dateiname ist zu lang.

                    D. h.: Das Problem liegt nicht an Delphi.

                    Gibt es denn auf Deinem Computer tatsächlich bereits einen Verzeichnisbaum, der insgesamt länger als 256 Zeichen ist, und wie ist er entstanden?


                    Gruß frauwue
                    docendo discimus

                    Comment


                    • #11
                      Fein. Dann sind wir jetzt auf dem selben Stand!

                      Ja, diese Verzeichnisse gibt es wirklich. Allerdings nicht auf meinem Rechner, sondern auf dem Server im Büro. Das ist ein Windows 2003SBS mit NTFS-formatierten Platten, die im Netz freigegeben sind.

                      Clients sind Windows 2000 und XP.

                      Ich selbst bin mit diesem Thema bisher nicht in Kontakt gekommen, da es bisher ja auch kein Problem gab. Ich betreue nur gelegentlich ein bisschen das Netzwerk. Ansonsten bin ich anderweitig Softwareentwickler im kaufmännischen Bereich. Da habe ich mit solchen Systemnahen Sachen nichts zu tun. Ich kämpfe also mehr mit Soll und Haben.

                      Es ist nun wohl so, dass für eingehende Anfragen oder Auftragskalkulationen jeweils ein eigenes Verzeichnis auf einer bestimmten Serverfreigabe angelegt wird. Dieser Verzeichnisname enthält schon Auftrags-/Angebotsnummer und Name/Ort des Auftraggebers.
                      Darunter wird dann ein Baum aufgebaut, in dem z.B. Emails gespeichert werden. Outlook verwendet als Mailnamen standardmäßig den Betreff. Da steht dann schonmal "wichtige Daten für dieses und jenes". Packt man die Anhänge aus, so wird der Betreff von Outlook als Unterverzeichnisname verwendet. Üblicherweise bekommt man ZIP-Dateien. Packt man diese aus, so wird der Name der ZIP-Datei von Windows als Unterverzeichnisname verwendet. Manche Archive sind so umfangreich, dass der Absender sie dann auch noch mit Unterverzeichnissen strukturiert hat...
                      Ganz Schlaue kopieren dann auch noch den gesamten Baum einer vom potentiellen Kunden zugesandten CD da hinein (Der Server hat ca. 1,5 TB Plattenplatz).

                      Wenn man überall nur die Standardvorgaben verwendet, also immer auf "weiter" klickt, statt selbst zu denken, und überall einigermassen sprechende Namen verwendet wurden, kommt es nun zu so irrsinnig langen Verzeichnisnamen.

                      Das Backupprogramm auf dem Server (Symantec BackupExcec) hat damit kein Problem. Auch andere Programme kommen damit zurecht. Man kann PDFs oder Texte mit MS-Office öffnen und auch wieder abspeichern.

                      Nun will ich ein Programm schreiben, mit dem diese Verzeichnisbäume DAU-sicher kopiert werden können. Das Ziel ist dann normalerweise entweder eine externe Festplatte oder ein Notebook, damit man offline arbeiten kann ohne zuviel über den aktuellen Ablageort der Daten nachdenken zu müssen. Die Daten auf dem Notebook liegen an der gleichen Stelle, wie sie auch im Netz liegen, wenn man angemeldet ist. Das erleichtert die Arbeit des gemeinen, nicht IT-affinen Büromenschen enorm.

                      Dieses Arbeitsprinzip hat sich über mehrere Jahre festgesetzt. Gerade in der letzten Zeit (2 Jahre?) wurden enorm viel Daten gesammelt.
                      Das jetzt umzustrukturieren, würde allerhand Konfusion erzeugen...

                      Zurück zum Thema:
                      Das es auch besser geht, beweist mir die Funktion CopyFileEx. Wenn man dort den Pfad mit dem Prefix "\\?\" angibt, wird die Unicodevariante (CopyFileExW) verwendet. Da sind dann Pfade bis 32000 Zeichen länge möglich (das eigentliche Limit von NTFS).
                      Diese Funktion gibt es ab Windows-NT. Für Kompatibilität mit Win98 etc. braucht man von MS die Unicode-Extensions.

                      Ich suche nun auch andere Verwaltungsfunktionen / Schalter, mit denen ich die Dateien mit Pfaden im Unicodeformat von Delphi 2007 aus verwalten kann.

                      Bisher habe ich die ganze Sache von Delphi aus beackert.
                      Heute Abend werde ich mir aber mal das .NET-Framework dazu ansehen. Vielleicht gibt es da was brauchbares.

                      Gruß,
                      nextX

                      Comment


                      • #12
                        moin,

                        isschamaninteressant!

                        um das file nach oben zu bekommen, würde ich nur einmal kopieren und dann nur noch mit
                        BOOL MoveFile(

                        LPCTSTR lpExistingFileName, // address of name of the existing file
                        LPCTSTR lpNewFileName // address of new name for the file
                        );
                        arbeiten.

                        Warum kann jetzt nicht der neue Baum auch als array produziert werden und dann schrittweise nach unten gegangen werden? Die o.g. win-function erzwingt laut sdk-hilfe den namen.

                        dir := './' + Newdir;
                        Du brauchst doch eigendlich, das, was du bisher angelegt hast nicht mehr.

                        gruss,bernhard

                        Comment


                        • #13
                          Danke für den Tipp!

                          MoveFile und das beschriebene Umwegverfahren ist zwar nicht direkt das, was ich eigentlich gesucht habe, aber ein guter Einstieg in die Liste von erweiterten Funktionen. Mir ist zwar nicht klar, warum man die bekannten Funktionen wie MkDir oder RmDir nicht weiter endwickelt hat, aber nun habe ich die neuen Funktionen mit ihren erweiterten Möglichkeiten entdeckt!
                          Beim Durchsuchen der Hilfe und des MSDN bzgl. MoveFile bin ich dann über Querverweise auf die Lösung gekommen:

                          Es geht mit CreateDirectoryW!

                          Es gibt gleich eine ganze Reihe von Funktionen, die sich mit der Erstellung von Directories beschäftigen. Dabei sind welche, die direkt den ganzen Pfad in einem Schlag anlegen, aber auch welche, die mit Unicode arbeiten.

                          Nun gelingt es mir tatsächlich, testweise einen Pfad mit über 800 Zeichen Länge anzulegen. Nur kann man den dann nicht mehr vollständig mit dem Explorer verwalten. Ab einer gewissen Hierarchietiefe mag er nicht mehr...

                          Nun muß ich nur mein eigentliches Programm dahingehend ändern, dass alle Pfade als WideString definiert werden. Ausserdem ist als Prefix ein "\\?\" voranzustellen (damit das OS die Unicodes verwendet) und alles natürlich NULL-terminiert und verpointert.

                          Bei den ganzen Tests ist mir klar geworden, dass NTFS zwar alle notwendigen Funktionen hat, diese aber nicht vom Explorer vollständig benutzt werden. Auch scheinen die Grenzen und Möglichkeiten bei lokalen und Netzlaufwerken leicht unterschiedlich zu sein.

                          Es gibt noch viel zu tun...

                          Danke auf jeden Fall für die Hilfe!

                          Gruß,
                          nextX

                          Comment


                          • #14
                            ein ähnliches Problem hatte ich auch. Nachdem ich den Gesamtpfad als "Widestring" definiert hatte war das Problem erledigt.
                            Vielleicht hilft Dir das ja auch.

                            Comment


                            • #15
                              Widestings sind nur im Delphiprogramm notwendig, um die langen Pfadnamen zu halten.
                              Das Problem sind die verschiedenen Funktionen, mit denen das Betriebssystem angesprochen wird, um diese Pfade zu bearbeiten.

                              Die Lösung steht im wesentlichen im Thread vor Deiner Mail.

                              Das Programm läuft nun schon einige Zeit relativ problemlos. Aber bei jeder weiteren Funktion (Löschen, verlinken, etc.) ist es ein ziemlicher Kampf, die passenden BS-Funktionen zu finden.

                              Mühselig, aber es geht.

                              Comment

                              Working...
                              X