Uri fullPath = new Uri(@"C:\RootFolder\SubFolder\MoreSubFolder\LastFolder\SomeFile.txt", UriKind.Absolute);
Uri relRoot = new Uri(@"C:\RootFolder\SubFolder\", UriKind.Absolute);
string relPath = relRoot.MakeRelativeUri(fullPath).ToString();
// relPath == @"MoreSubFolder\LastFolder\SomeFile.txt"
In your example, it's simply absPath.Substring(relativeTo.Length) . More elaborate example would require going back a few levels from the relativeTo , as follows:
public static partial class PathUtilities
{
/// <summary>
/// Rebases file with path <paramref name="fullPath"/> to folder with <paramref name="baseDir"/>.
/// </summary>
/// <param name="fullPath">Full file path (absolute)</param>
/// <param name="baseDir">Full base directory path (absolute)</param>
/// <returns>Relative path to file with respect to <paramref name="baseDir"/></returns>
/// <remarks>Paths are resolved by calling the <seealso cref="System.IO.Path.GetFullPath(string)"/> method before calculating the difference. This will flatten relative path fragments:
/// <code>
/// "c:\test\..\test2" => "c:\test2"
/// </code>
/// These path framents are expected to be created by concatenating a root folder with a relative path such as this:
/// <code>
/// var baseFolder = @"c:\test\";
/// var virtualPath = @"..\test2";
/// var fullPath = System.IO.Path.Combine(baseFolder, virtualPath);
/// </code>
/// The default file path for the current executing environment will be used for the base resolution for this operation, which may not be appropriate if the input paths are fully relative or relative to different
/// respective base paths. For this reason we should attempt to resolve absolute input paths <i>before</i> passing through as arguments to this method.
/// </remarks>
static public string MakeRelative(string fullPath, string baseDir)
{
String pathSep = "\\";
String itemPath = Path.GetFullPath(fullPath);
String baseDirPath = Path.GetFullPath(baseDir); // If folder contains upper folder references, they get resolved here. "c:\test\..\test2" => "c:\test2"
String[] p1 = Regex.Split(itemPath, "[\\\\/]").Where(x => x.Length != 0).ToArray();
String[] p2 = Regex.Split(baseDir, "[\\\\/]").Where(x => x.Length != 0).ToArray();
int i = 0;
for (; i < p1.Length && i < p2.Length; i++)
if (String.Compare(p1[i], p2[i], true) != 0) // Case insensitive match
break;
if (i == 0) // Cannot make relative path, for example if resides on different drive
return itemPath;
String r = String.Join(pathSep, Enumerable.Repeat("..", p2.Length - i).Concat(p1.Skip(i).Take(p1.Length - i)));
return r;
}
}
5条答案
按热度按时间gab6jxml1#
是的,您可以这样做,这很简单,将路径视为URI:
3z6pesqy2#
In your example, it's simply
absPath.Substring(relativeTo.Length)
.More elaborate example would require going back a few levels from the
relativeTo
, as follows:The algorithm to make a relative path would look as follows:
"C:\RootFolder\SubFolder\"
)relativeTo
(in this case, it is 2:"Sibling\Child\"
)..\
for each remaining folderThe end result looks like this:
wxclj1h53#
在以下git仓库中搜索
makeRelative
后:https://github.com/tapika/syncProj/blob/8ea41ebc11f538a22ed7cfaf59a8b7e0b4c3da37/syncProj.cs#L1685我们找到了这个解决方案,它在经过一点测试后通过文档得到了增强;)
字符串
此方法的用法:
结果:
0pizxfdo4#
对于现代实现,请使用
System.IO.Path.GetRelativePath
路径.GetRelativePath(字符串,字符串)方法
返回从一个路径到另一个路径的相对路径。
在.Net Core 2.0(2017年8月)和.Net Standard 2.1(2018年5月)中引入,实现与@TarmoPikaro发布的答案非常相似
此方法的用法:
结果:
与answer from @TarmoPikaro一样,此实现使用
System.IO.Path.GetFullPath
来解析在比较之前可能经过的相对路径。这样做的目的是解析通过在 base path 后面附加 relative path 构建的路径,这是我们在调用
GetRelativePath()
之前经常做的事情。这是意料之中的,但如果输入路径是完全相对的,路径将被解析为当前工作文件夹,在我的测试应用程序中,这看起来像这样:
在大多数情况下,这会导致
MakeRelative
产生意外的结果。因此,实际上应该先使用连接或自己调用GetFullPath
来解析输入参数。beq87vna5#
.NET Core和.NET在标准库中提供了
System.IO.Path.GetRelativePath(string, string)
方法。如果您需要在较早的.NET Framework项目中使用该方法,则可以使用以下多边形填充,它非常接近标准BCL行为:为了提供与
System.IO.Path.GetRelativePath(string, string)
方法相同的行为,上面的代码涵盖了相当多的边缘情况。