How to get relative path from absolute path

前端 未结 23 2217
既然无缘
既然无缘 2020-11-22 11:52

There\'s a part in my apps that displays the file path loaded by the user through OpenFileDialog. It\'s taking up too much space to display the whole path, but I don\'t want

23条回答
  •  南方客
    南方客 (楼主)
    2020-11-22 12:46

    .NET Core 2.0 Answer

    .NET Core 2.0 has Path.GetRelativePath which can be used like so:

    var relativePath = Path.GetRelativePath(
        @"C:\Program Files\Dummy Folder\MyProgram",
        @"C:\Program Files\Dummy Folder\MyProgram\Data\datafile1.dat");
    

    In the above example, the relativePath variable is equal to Data\datafile1.dat.

    Alternative .NET Answer

    @Dave's solution does not work when the file paths do not end with a forward slash character (/) which can happen if the path is a directory path. My solution fixes that problem and also makes use of the Uri.UriSchemeFile constant instead of hard coding "FILE".

    /// 
    /// Creates a relative path from one file or folder to another.
    /// 
    /// Contains the directory that defines the start of the relative path.
    /// Contains the path that defines the endpoint of the relative path.
    /// The relative path from the start directory to the end path.
    ///  or  is null.
    /// 
    /// 
    public static string GetRelativePath(string fromPath, string toPath)
    {
        if (string.IsNullOrEmpty(fromPath))
        {
            throw new ArgumentNullException("fromPath");
        }
    
        if (string.IsNullOrEmpty(toPath))
        {
            throw new ArgumentNullException("toPath");
        }
    
        Uri fromUri = new Uri(AppendDirectorySeparatorChar(fromPath));
        Uri toUri = new Uri(AppendDirectorySeparatorChar(toPath));
    
        if (fromUri.Scheme != toUri.Scheme)
        {
            return toPath;
        }
    
        Uri relativeUri = fromUri.MakeRelativeUri(toUri);
        string relativePath = Uri.UnescapeDataString(relativeUri.ToString());
    
        if (string.Equals(toUri.Scheme, Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase))
        {
            relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
        }
    
        return relativePath;
    }
    
    private static string AppendDirectorySeparatorChar(string path)
    {
        // Append a slash only if the path is a directory and does not have a slash.
        if (!Path.HasExtension(path) &&
            !path.EndsWith(Path.DirectorySeparatorChar.ToString()))
        {
            return path + Path.DirectorySeparatorChar;
        }
    
        return path;
    }
    

    Windows Interop Answer

    There is a Windows API called PathRelativePathToA that can be used to find a relative path. Please note that the file or directory paths that you pass to the function must exist for it to work.

    var relativePath = PathExtended.GetRelativePath(
        @"C:\Program Files\Dummy Folder\MyProgram",
        @"C:\Program Files\Dummy Folder\MyProgram\Data\datafile1.dat");
    
    public static class PathExtended
    {
        private const int FILE_ATTRIBUTE_DIRECTORY = 0x10;
        private const int FILE_ATTRIBUTE_NORMAL = 0x80;
        private const int MaximumPath = 260;
    
        public static string GetRelativePath(string fromPath, string toPath)
        {
            var fromAttribute = GetPathAttribute(fromPath);
            var toAttribute = GetPathAttribute(toPath);
    
            var stringBuilder = new StringBuilder(MaximumPath);
            if (PathRelativePathTo(
                stringBuilder,
                fromPath,
                fromAttribute,
                toPath,
                toAttribute) == 0)
            {
                throw new ArgumentException("Paths must have a common prefix.");
            }
    
            return stringBuilder.ToString();
        }
    
        private static int GetPathAttribute(string path)
        {
            var directory = new DirectoryInfo(path);
            if (directory.Exists)
            {
                return FILE_ATTRIBUTE_DIRECTORY;
            }
    
            var file = new FileInfo(path);
            if (file.Exists)
            {
                return FILE_ATTRIBUTE_NORMAL;
            }
    
            throw new FileNotFoundException(
                "A file or directory with the specified path was not found.",
                path);
        }
    
        [DllImport("shlwapi.dll", SetLastError = true)]
        private static extern int PathRelativePathTo(
            StringBuilder pszPath,
            string pszFrom,
            int dwAttrFrom,
            string pszTo,
            int dwAttrTo);
    }
    

提交回复
热议问题