如何在.NET中获取绝对或标准化的文件路径?

63

如何用最小的力气(如果可能的话,使用一些已经存在的工具)将路径转换成 c:\aaa\ccc,例如 c:\aaa\bbb\..\ccc

4个回答

77

我会这样写:

public static string NormalizePath(string path)
{
    return Path.GetFullPath(new Uri(path).LocalPath)
               .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
               .ToUpperInvariant();
}

这应该处理一些场景,例如:

  1. URI及其中潜在的转义字符,例如

    file:///C:/Test%20Project.exe -> C:\TEST PROJECT.EXE

  2. 使用点指定当前或父目录的路径段

    c:\aaa\bbb\..\ccc -> C:\AAA\CCC

  3. 波浪线缩短的(长)路径

    C:\Progra~1\ -> C:\PROGRAM FILES

  4. 不一致的目录分隔符

    C:/Documents\abc.txt -> C:\DOCUMENTS\ABC.TXT

除了上述情况外,它可以忽略大小写、末尾的 \ 目录分隔符等。


1
好的、简洁的路径规范化解决方案,正是我所寻找的。+1 - Syon
33
为了让代码具备可移植性,请勿在任何代码中使用ToUpper()和类似方法。世界上存在区分大小写的文件系统。如果您要向用户展示这些值,保留大小写并使用不区分大小写的排序和比较方式更为合适。除此之外,看起来不错。 - dhasenan
2
这取决于您对“规范”的确切理解,但由于Windows将文件路径视为不区分大小写,我认为您确实需要进行大小写转换,否则同一文件可能会有多个“规范”路径。我更喜欢小写。 - Andy
6
另一方面,如果有人使用这种“NormalizePath”的变体来复制或移动文件到某个位置,她/他很可能希望大小写不会改变。作为用户,我会禁止任何这样的程序更改我精心保留的命名系统。 - Sebastian Mach
1
因为它确实很重要:不要改变命名大小写!从用户视觉角度来看,这是不礼貌的,有时甚至会带来问题。如果需要进行“规范比较”的原因,那么就应该使用字符串不区分大小写比较(可能带有字典或其他内容):在Windows文件系统API中,CI访问是在“规范”之后处理的! - user2864740
显示剩余5条评论

63

Path.GetFullPath也许可以?


4
我不相信这一定会返回规范名称。它只保证返回的名称可以用于绝对或相对地引用文件。 - JaredPar
6
Path.GetFullPath(@"c:\aaa\bbb..\ccc") = c:\aaa\ccc - 对我来说已经足够好了。 - mark
12
@Henk:路径工具实际上不应检查文件是否有效,甚至不应触及文件系统(但某些情况下会这样做)。 - leppie
1
@My-Name-Is:这完全取决于你如何使用它。 - leppie
1
@My-Name-Is:这就是GetFullPath应该做的事情。注意,Path.GetFullPath(@"..\aaa")返回无意义的"C:..\aaa",而Path.GetFullPath(@"..\aaa")返回相对于您的Path.CurrentDirectory()的绝对路径。 - Chris F Carroll
显示剩余5条评论

29

规范化是 .NET 中 Uri 类的主要职责之一。

var path = @"c:\aaa\bbb\..\ccc";
var canonicalPath = new Uri(path).LocalPath; // c:\aaa\ccc

那么我假设这个检查是为了确保路径实际上存在? - ashes999
6
不,Uri类只负责生成路径。与这些路径相关的系统不被考虑在内。一旦你通过我的答案中的方法获取了路径,你仍然需要通过File类(或其他方式)检查它是否存在。 - bdukes
8
请注意,该程序仍然无法规范化驱动器盘符的大小写(例如 "C:" 和 "c:" 都不会被改变)。因此,从某种意义上说,这并不真正是“规范化”的,至少它不是唯一的。 - Alastair Maw
3
由于Windows文件系统是大小写不敏感的,假设一个路径是“规范”的,那么任何其他只有大小写不同的路径都是规范和等效的,即使存在大小写差异。用户应该在相关情况下使用大小写不敏感的字符串比较,因为所有大小写不同的形式实际上是相同的。 - user2864740
1
注意,URI类可能会对字符进行编码,例如+、空格和其他字符。 - mihca

1

FileInfo对象在这里也可以提供帮助。(https://learn.microsoft.com/en-us/dotnet/api/system.io.fileinfo?view=net-5.0)

var x = Path.Combine(@"C:\temp", "..\\def/abc");
var y = new FileInfo(x).FullName; // "C:\\def\\abc"

如果你想控制文件和目录的区别,FileInfo与DirectoryInfo也可以帮助解决问题。

但如果你只需要字符串,Path.GetFullPath更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接