Path.Combine : "Rep1\Rep2\File.ext" != "\Rep1\Rep2\File.ext"
Certains s'étonnent devant le retour de la méthode Path.Combine pour le code suivant :
String path1 = @"C:\Rep0";
String path2 = @"\Rep1\Rep2\File.ext";
String path = Path.Combine(path1, path2);
En effet, path contiendra "\Rep1\Rep2\File.ext" alors que certains s'attendent à avoir "C:\Rep0\Rep1\Rep2\File.ext".
Pourquoi alors qu'on nous répète si souvent qu'un des avantages d'utiliser Path.Combine est de s'affranchir de la vérification manuelle de l'existence ou non d'un \ en fin de chemin de répertoire, les codes suivants ne retournent pas tous la même chose : "C:\Rep0\Rep1\Rep2\File.ext" ?
String path1;
String path2;
String path;
path1 = @"C:\Rep0";
path2 = @"\Rep1\Rep2\File.ext";
path = Path.Combine(path1, path2); // \Rep1\Rep2\File.ext
path1 = @"C:\Rep0";
path2 = @"Rep1\Rep2\File.ext";
path = Path.Combine(path1, path2); // C:\Rep0\Rep1\Rep2\File.ext
path1 = @"C:\Rep0\";
path2 = @"\Rep1\Rep2\File.ext";
path = Path.Combine(path1, path2); // \Rep1\Rep2\File.ext
path1 = @"C:\Rep0\";
path2 = @"Rep1\Rep2\File.ext";
path = Path.Combine(path1, path2); // C:\Rep0\Rep1\Rep2\File.ext
Ce comportement est conforme à ce qui est annoncé dans la documentation de Path.Combine :
"[...]Si path2 inclut une racine, path2 est retourné.[...]" / "[...]If path2 includes a root, path2 is returned.[...]"
Donc "\Rep1\Rep2\File.ext" est considéré comme possédant une racine ? Il s'agit donc d'un chemin absolu ?
Personnellement je le considère plutôt comme étant à mi chemin entre le chemin relatif et le chemin absolu : là où "Rep1\Rep2\File.ext" est relatif au répertoire courant, "\Rep1\Rep2\File.ext" est en fait relatif à la racine du répertoire courant.
Même si on ne l'est que de la racine, on reste dépendant du répertoire courant.
Exemple, si le répertoire courant est "C:\Rep0", le chemin complet (voir Path.GetFullPath ou directement GetFullPathName / GetFullPathNameTransacted) de
- "Rep1\Rep2\File.ext" est "C:\Rep0\Rep1\Rep2\File.ext"
- "\Rep1\Rep2\File.ext" est "C:\Rep1\Rep2\File.ext"
Mais dans les faits, il ne s'agit pas d'un chemin relatif, comme le spécifie la section "Relative Paths" de cette page de la documentation :
"[...]A file name is relative to the current directory if it does not begin with one of the following:
- A drive name, which is either a drive letter followed by a colon, or a UNC name.
- A directory name separator (backslash), for example, \subdirectory).
[...]"
Ce type de chemin est d'ailleurs tout à fait utilisable directement avec SetCurrentDirectory, et la documentation de GetCurrentDirectory aborde elle aussi le sujet :
"In certain rare cases, if the specified directory is on the current drive, the function might omit the drive letter and colon from the path. Therefore, the size that is returned by the function might be two characters less than the size of the specified string, not including the terminating null character. This behavior might occur in edge situations such as in a services application. If you need the drive letter, make a subsequent call to GetFullPathName to retrieve the drive letter."
Au passage si quelqu'un sait comment reproduire ce comportement sur GetCurrentDirectory, je prends.
Vous l'utilisez aussi probablement dans cmd ou PowerShell si vous voulez positionner le répertoire courant à la racine : vous tapez "cd \", pas "cd C:\".
Bref, je résume : "Rep1\Rep2\File.ext" != "\Rep1\Rep2\File.ext"
Naming a File (Windows)
Path.Combine Method (System.IO)
Path.GetFullPath Method (System.IO)
GetFullPathName Function (Windows) / GetFullPathNameTransacted Function (Windows)
GetCurrentDirectory Function (Windows)
SetCurrentDirectory Function (Windows)
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :