2009-03-26 18 views
11

Mögliche Duplizieren:
Best way to determine if two path reference to same file in C/C++Normalisieren Dateipfad mit WinAPI

mit möglicherweise unterschiedlichen Gehäusen zwei Dateipfade Strings gegeben und Schrägstrichen ('\' vs '/'), ist es eine schnelle Art und Weise (das beinhaltet nicht das Schreiben meiner eigenen Funktion), um beide Pfade auf die gleiche Form zu normalisieren oder zumindest auf Äquivalenz zu testen?

Ich bin auf WinAPI und Standard C++ beschränkt. Alle Dateien sind lokal.

Antwort

4

Abhängig davon, ob die Pfade relativ sein können oder ".." oder Knotenpunkte oder UNC-Pfade enthalten, ist dies möglicherweise schwieriger als Sie denken. Der beste Weg wäre, die GetFileInformationByHandle() Funktion wie in this answer zu verwenden.

Bearbeiten: Ich stimme dem Kommentar von RBertig, dass dies schwer zu tun unmöglich werden kann, wenn die Pfade nicht auf eine lokale Datei zeigen. Jeder Kommentar, wie dieser Fall sicher gehandhabt wird, würde sehr geschätzt werden.

+0

Solange die beiden Pfade in Dateien auf demselben Computer aufgelöst werden, sieht es so aus, als ob GetFileInformationByHandle() die richtige Antwort ist.Wenn sie zu verschiedenen Computern auflösen, sehe ich keine Garantie, und ich sehe auch keinen trivialen Weg, einen zu bekommen. Es ist nicht unbedingt einfach, dies zu testen. – RBerteig

+0

Alle Dateien sind in meinem Fall lokal, das funktioniert also. –

+0

@RBertig: Ich sehe auch keinen trivialen Weg, um einen zu bekommen. Aber ich fand ein sehr nicht-triviales und legte es in eine Antwort; Schau mal. Selbst dieser ist meist nur narrensicher, aber für die meisten Menschen sollte er mehr als genug sein. – steveha

3

Es gibt seltsame Fälle. Zum Beispiel ist "c: \ windows .. \ data \ meinedatei.txt" dasselbe wie "c: \ data. \ Meinedatei.txt" und "c: \ data \ meinedatei.txt". Sie können eine beliebige Anzahl von "\." Und "\ .." darin eingeben. Sie können sich die Windows API-Funktion GetFullPathName ansehen. Es könnte Kanonisierung für Sie tun.

6

Darf ich vorschlagen PathCanonicalize?

+0

Es sieht nicht so aus, als ob es Knotenpunkte oder UNC-Pfade adressiert ... aber es sieht nützlich aus, darüber zu wissen. – RBerteig

+0

Das ist die Methode, nach der ich gesucht habe. Nicht GetFullPathName. –

+6

Nachdem ich diese Antwort angesehen hatte, versuchte ich mit PathCanonicalize() und stellte fest, dass es schrecklich kaputt ist. 'PathCanonicalize (" ../ foo.txt ")' gibt immer '/ foo.txt' zurück! PathCanonicalize() führt nur eine triviale Bearbeitung der Zeichenfolge durch, und die obige broken-ness ist dokumentiertes Verhalten. Nutzlos. Ich werde eine andere Antwort mit dem, was ich gefunden habe, posten. – steveha

6

Ich fand einen Blogeintrag mit der gründlichsten, sogar ausgefeiltesten Funktion, die ich je gesehen habe, um dieses Problem zu lösen. Es behandelt alles, sogar schreckliche Ecke Fällen wie V:foo.txt, wo Sie den subst Befehl verwendet, um V: zu Z: zu mappen, aber Sie bereits subst verwendet, um Z: auf ein anderes Laufwerk zu mappen; Es läuft solange, bis alle subst Befehle abgewickelt sind. URL:

http://pdh11.blogspot.com/2009/05/pathcanonicalize-versus-what-it-says-on.html

Mein Projekt ist reiner C-Code, und diese Funktion ist C++. Ich habe angefangen, es zu übersetzen, aber dann fand ich heraus, dass ich den normalisierten Pfad, den ich wollte, mit einem Funktionsaufruf erhalten konnte: GetLongPathName(). Dies wird nicht mit den schrecklichen Fällen umgehen, aber es hat meine unmittelbaren Bedürfnisse behandelt. Ich

entdeckt, dass GetLongPathName("foo.txt") gibt nur foo.txt, sondern nur durch ./ an den Dateinamen vorangestellt habe ich die Erweiterung auf normierter Form:

GetLongPathName("./foo.txt"), wenn C:\Users\steveha im Verzeichnis ausgeführt, kehrt C:\Users\steveha\foo.txt.

Also, in Pseudo-Code:

, wenn das zweite Zeichen des Pfadnamen ist ':' oder das erste Zeichen ist '/' oder '\', rufen Sie einfach GetLongPathName() sonst, kopieren "./" in einen temporären Puffer, dann kopiere den Dateinamen in temp buffer + 2, um eine Kopie des Dateinamens mit vorangestelltem "./" zu erhalten und dann GetLongPathName() aufzurufen.

+0

Nun, zumindest dieser Beitrag bietet Code, der aussieht, als ob er alle schweren Arbeiten erledigt. Es behandelt sicherlich mehr Ecken Fälle und vollständiger, als Sie erwarten würden. Offensichtlich hat sich der Autor diese Probleme ein paar Mal in den Fingern verbrannt ... Ihr einfacher Fallback ist wahrscheinlich für die meisten Fälle gut genug und lässt die exotischen Fälle dazu dienen, Software zu täuschen, die etwas zu täuschen braucht. – RBerteig

+0

Meine Benutzer haben wahrscheinlich noch nie von dem Befehl 'subst' gehört, und mein einfacher C-Code hat bis jetzt perfekt funktioniert. – steveha

+0

Die große Überraschung für uns Oldtimer ist, dass 'subst' noch existiert ... es ist sogar in Win7 64bit vorhanden, aber es stammt aus DOS 5.0, wenn nicht früher. Win7 kommt mit einer Reihe von JUNCTIONS für Abwärtskompatibilität. Das gibt einige meiner älteren Perl-Skripte, die durch das Dateisystem wandern, passend, da sie nicht ganz Verzeichnisse sind und sicherlich keine Dateien sind. Ein Beispiel ist, dass 'C: \ Dokumente und Einstellungen' eine JUNCTION ist, die' C: \ Benutzer' zugeordnet ist. – RBerteig