如何根据一个绝对文件路径生成一个相对文件路径

如何根据一个绝对文件路径生成一个相对文件路径

发布于 2018-06-07 11:30 更新于 2018-09-01 00:04

日常的开发中,获取绝对文件路径才是主流吧!连 Path.GetFullPath 这种生成绝对路径的方法都已经成为 .NET Standard 的一部分了。

然而,生成相对路径依然有用——比如你的配置文件是相对于工作目录的,必须这个路径是输出给用户看的……


那么,既然 Path 没有生成相对路径的方法,还能怎么生成相对路径呢?别跟我说自己去做字符串比较……

Uri 却提供了 MakeRelativeUri 方法,可以生成一个路径到另一个路径的相对路径。于是我们可以写出这样的代码:

public static string MakeRelativePath(string fromPath, string toPath)
{
    var fromUri = new Uri(fromPath);
    var toUri = new Uri(toPath);
    var relativeUri = fromUri.MakeRelativeUri(toUri);
    return Uri.UnescapeDataString(relativeUri.ToString());
}

运行传入 C:\Users\walterlv\OpenSource\DemoC:\Users\walterlv\OpenSource\Demo\build\config.xml。结果,竟然得到的相对路径是:Demo/build/config.xml

  1. 那个 Demo 明明是两者共有的路径部分,却存在于相对路径中;
  2. 生成的路径使用 /,而不是 Windows 系统使用的 \

于是我们需要分别进行这两个处理。对于前者,我们必须让 Uri 意识到这是一个文件夹才能让最终生成的路径不带这个重复的部分;对于后者,我们需要进行路径连接符转换。于是最终的代码我整理成了如下方法:

public static string MakeRelativePath(string fromPath, string toPath)
{
    if (string.IsNullOrEmpty(fromPath)) throw new ArgumentNullException(nameof(fromPath));
    if (string.IsNullOrEmpty(toPath)) throw new ArgumentNullException(nameof(toPath));

    var fromUri = new Uri(fromPath);
    var toUri = new Uri(toPath);

    if (fromUri.Scheme != toUri.Scheme)
    {
        // 不是同一种路径,无法转换成相对路径。
        return toPath;
    }
    
    if (fromUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)
        && !fromPath.EndsWith("/") && !fromPath.EndsWith("\\"))
    {
        // 如果是文件系统,则视来源路径为文件夹。
        fromUri = new Uri(fromPath + Path.DirectorySeparatorChar);
    }

    var relativeUri = fromUri.MakeRelativeUri(toUri);
    var relativePath = Uri.UnescapeDataString(relativeUri.ToString());

    if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase))
    {
        relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
    }

    return relativePath;
}

现在重新传入 C:\Users\walterlv\OpenSource\DemoC:\Users\walterlv\OpenSource\Demo\build\config.xml。结果,已经能够得到:build\config.xml 了。


参考资料

本文会经常更新,请阅读原文: https://walterlv.com/post/make-relative-file-path.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏GuZhenYin

ASP.NET Core文件上传与下载(多种上传方式)

前言 前段时间项目上线,实在太忙,最近终于开始可以研究研究ASP.NET Core了. 打算写个系列,但是还没想好目录,今天先来一篇,后面在整理吧. ASP.N...

64060
来自专栏恰童鞋骚年

ASP.Net请求处理机制初步探索之旅 - Part 3 管道

开篇:上一篇我们了解了一个ASP.Net页面请求的核心处理入口,它经历了三个重要的入口,分别是:ISAPIRuntime.ProcessRequest()、Ht...

16720
来自专栏菩提树下的杨过

用VS2010调试微软开放的部分源码

msdn上有一篇讲解如何用vs2008调试源码的文章:http://blogs.msdn.com/b/sburke/archive/2008/01/16/con...

24150
来自专栏草根专栏

从头编写 asp.net core 2.0 web api 基础框架 (1)

工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net c...

70770
来自专栏NetCore

【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

HTTP is not just for serving up web pages. It’s also a powerful platform for bui...

26750
来自专栏蘑菇先生的技术笔记

Net作业调度(五)—quartz.net动态添加job设计

32560
来自专栏me的随笔

ASP.NET MVC5请求管道和生命周期

请求管道是一些用于处理HTTP请求的模块组合,在ASP.NET中,请求管道有两个核心组件:IHttpModule和IHttpHandler。所有的HTTP请求都...

15730
来自专栏木宛城主

开源依旧:再次分享一个进销存系统

开篇 我之前发过一篇博文《两天完成一个小型工程报价系统(三层架构)》,不少朋友向我要源码学习,后来久而久之忘记回复了。今天我再分享一个进销存系统,只为学习,没...

1.1K100
来自专栏恰童鞋骚年

.NET Core微服务之基于MassTransit实现数据最终一致性(Part 2)

  在上一篇中,我们了解了MassTransit这个开源组件的基本用法,这一篇我们结合一个小案例来了解在ASP.NET Core中如何借助MassTransit...

16840
来自专栏LanceToBigData

HttpClient(二)HttpClient使用Ip代理与处理连接超时

前言   其实前面写的那一点点东西都是轻轻点水,其实HttpClient还有很多强大的功能:   (1)实现了所有 HTTP 的方法(GET,POST,PUT,...

45380

扫码关注云+社区

领取腾讯云代金券