В зависимости от Вашего приложения и объема cfg файла, файл свойств мог бы быть самым легким. Уверенный это не столь изящно как xml, но это, конечно, легче.
Alright so in my case I don't have some of the tougher edge cases (fullPath and relativePath mixing network map locations, super long filenames). What I ended up doing was creating the class below
public class PathUtil
{
static public string NormalizeFilepath(string filepath)
{
string result = System.IO.Path.GetFullPath(filepath).ToLowerInvariant();
result = result.TrimEnd(new [] { '\\' });
return result;
}
public static string GetRelativePath(string rootPath, string fullPath)
{
rootPath = NormalizeFilepath(rootPath);
fullPath = NormalizeFilepath(fullPath);
if (!fullPath.StartsWith(rootPath))
throw new Exception("Could not find rootPath in fullPath when calculating relative path.");
return "." + fullPath.Substring(rootPath.Length);
}
}
It seems to work pretty well. At least, it passes these NUnit tests:
[TestFixture]
public class PathUtilTest
{
[Test]
public void TestDifferencesInCapitolizationDontMatter()
{
string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
string format2 = PathUtil.NormalizeFilepath("c:\\WindowS\\System32");
Assert.AreEqual(format1, format2);
}
[Test]
public void TestDifferencesDueToBackstepsDontMatter()
{
string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
string format2 = PathUtil.NormalizeFilepath("c:\\Program Files\\..\\Windows\\System32");
Assert.AreEqual(format1, format2);
}
[Test]
public void TestDifferencesInFinalSlashDontMatter()
{
string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
string format2 = PathUtil.NormalizeFilepath("c:\\windows\\system32\\");
Console.WriteLine(format1);
Console.WriteLine(format2);
Assert.AreEqual(format1, format2);
}
[Test]
public void TestCanCalculateRelativePath()
{
string rootPath = "c:\\windows";
string fullPath = "c:\\windows\\system32\\wininet.dll";
string expectedResult = ".\\system32\\wininet.dll";
string result = PathUtil.GetRelativePath(rootPath, fullPath);
Assert.AreEqual(expectedResult, result);
}
[Test]
public void TestThrowsExceptionIfRootDoesntMatchFullPath()
{
string rootPath = "c:\\windows";
string fullPath = "c:\\program files\\Internet Explorer\\iexplore.exe";
try
{
PathUtil.GetRelativePath(rootPath, fullPath);
}
catch (Exception)
{
return;
}
Assert.Fail("Exception expected");
}
}
The test cases rely on certain files existing.. these files are common on most Windows installs but your mileage may vary.
Сначала попробуйте Path.GetFullPath, а затем сравнение строк.
Я попытался найти способ сделать это с длинными путями к файлам, но я просто не получаю удовлетворительных результатов, потому что вы теряете канонизацию путей в Win32 при использовании длинных версий стандартного файла системные вызовы. Таким образом, это решение не обязательно работает с вещами, длина которых превышает 260 символов, но в противном случае это управляемый код и мозг просто мертв.
string path1 = @"c:\folder\subdirectory\something.text";
string path2 = @"c:\folder\foo\..\something.text";
Uri value = new Uri(path1);
Uri value2 = new Uri(path2);
Uri result = value.MakeRelativeUri(value2);
Console.WriteLine(result.OriginalString);
Что дает
../something.text
Теперь имена 8.3 (короткие имена) для путей - это другое дело. Насколько я понимаю, эти пути хранятся в файловой системе, и вы должны использовать win32 для их получения. Кроме того, их можно отключить, поэтому нет никакой гарантии, что они там есть. Чтобы получить длинный путь из короткого пути, вы вызываете GetLongPathName в Kernel32.dll. Это также означает, что файл должен существовать.
Если вы хотите это сделать, то этот сайт - ваш друг. GetLongPathName
Я сделал это с помощью следующей функции. Первый параметр - это каталог, из которого мы ищем, Второй параметр - это путь назначения. Оба пути могут быть относительными. Функция не оптимизирована, но выполняет свою работу.
private string _GetRelativePath(string fromPath, string toPath)
{
string fromFull = Path.Combine(Environment.CurrentDirectory, fromPath);
string toFull = Path.Combine(Environment.CurrentDirectory, toPath);
List<string> fromParts = new List<string>
fromFull.Split(Path.DirectorySeparatorChar));
List<string> toParts =
new List<string>(toFull.Split(Path.DirectorySeparatorChar));
fromParts.RemoveAll(string.IsNullOrEmpty);
toParts.RemoveAll(string.IsNullOrEmpty);
// Remove all the same parts in front
bool areRelative = false;
while ( fromParts.Count > 0 && toParts.Count > 0 &&
StringComparer.OrdinalIgnoreCase.Compare(fromParts[0], toParts[0]) == 0 )
{
fromParts.RemoveAt(0);
toParts.RemoveAt(0);
areRelative = true;
}
if ( !areRelative )
return toPath;
// Number of remaining fromParts is number of parent dirs
StringBuilder ret = new StringBuilder();
for ( int i = 0; i < fromParts.Count; i++ )
{
if ( ret.Length > 0 )
ret.Append(Path.DirectorySeparatorChar);
ret.Append("..");
}
// And the remainder of toParts
foreach (string part in toParts)
{
if ( ret.Length > 0 )
ret.Append(Path.DirectorySeparatorChar);
ret.Append(part);
}
return ret.ToString();
}