我正在编写一个控制台实用程序来对命令行上指定的文件进行一些处理,但是我遇到了一个我无法通过Google/Stack Overflow解决的问题.如果指定了完整路径(包括驱动器号),如何将该路径重新格式化为相对于当前工作目录?
必须有类似于VirtualPathUtility.MakeRelative函数的东西,但如果有,它就会让我失望.
如果你不介意切换斜线,你可以[ab]使用Uri
:
Uri file = new Uri(@"c:\foo\bar\blop\blap.txt"); // Must end in a slash to indicate folder Uri folder = new Uri(@"c:\foo\bar\"); string relativePath = Uri.UnescapeDataString( folder.MakeRelativeUri(file) .ToString() .Replace('/', Path.DirectorySeparatorChar) );
string GetRelativePath(string filespec, string folder) { Uri pathUri = new Uri(filespec); // Folders must end in a slash if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) { folder += Path.DirectorySeparatorChar; } Uri folderUri = new Uri(folder); return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar)); }
您可以使用Environment.CurrentDirectory
获取当前目录,并FileSystemInfo.FullPath
获取任何位置的完整路径.因此,完全限定当前目录和相关文件,然后检查完整文件名是否以目录名开头 - 如果是,只需根据目录名的长度获取相应的子字符串.
这是一些示例代码:
using System; using System.IO; class Program { public static void Main(string[] args) { string currentDir = Environment.CurrentDirectory; DirectoryInfo directory = new DirectoryInfo(currentDir); FileInfo file = new FileInfo(args[0]); string fullDirectory = directory.FullName; string fullFile = file.FullName; if (!fullFile.StartsWith(fullDirectory)) { Console.WriteLine("Unable to make relative path"); } else { // The +1 is to avoid the directory separator Console.WriteLine("Relative path: {0}", fullFile.Substring(fullDirectory.Length+1)); } } }
我不是说它是世界上最强大的东西(符号链接可能会让它混淆)但是如果这只是一个偶尔会使用的工具,那也许没关系.
public string MakeRelativePath(string workingDirectory, string fullPath) { string result = string.Empty; int offset; // this is the easy case. The file is inside of the working directory. if( fullPath.StartsWith(workingDirectory) ) { return fullPath.Substring(workingDirectory.Length + 1); } // the hard case has to back out of the working directory string[] baseDirs = workingDirectory.Split(new char[] { ':', '\\', '/' }); string[] fileDirs = fullPath.Split(new char[] { ':', '\\', '/' }); // if we failed to split (empty strings?) or the drive letter does not match if( baseDirs.Length <= 0 || fileDirs.Length <= 0 || baseDirs[0] != fileDirs[0] ) { // can't create a relative path between separate harddrives/partitions. return fullPath; } // skip all leading directories that match for (offset = 1; offset < baseDirs.Length; offset++) { if (baseDirs[offset] != fileDirs[offset]) break; } // back out of the working directory for (int i = 0; i < (baseDirs.Length - offset); i++) { result += "..\\"; } // step into the file path for (int i = offset; i < fileDirs.Length-1; i++) { result += fileDirs[i] + "\\"; } // append the file result += fileDirs[fileDirs.Length - 1]; return result; }
这段代码可能不是防弹,但这就是我提出的.它更健壮一点.它需要两条路径并返回路径B作为相对于路径A的路径.
例:
MakeRelativePath("c:\\dev\\foo\\bar", "c:\\dev\\junk\\readme.txt") //returns: "..\\..\\junk\\readme.txt" MakeRelativePath("c:\\dev\\foo\\bar", "c:\\dev\\foo\\bar\\docs\\readme.txt") //returns: "docs\\readme.txt"