Вроде тривиальная задача. Вот есть у вас путь к файлу, типа:
D:/Temp/Resources/add.png
А так же есть путь к папке, типа:
D:/Temp/Templates/Resources
Как получить относительный путь для файла с точки зрения папки
D:/Temp/Templates/Resources? Т.е. должно получиться:
../../Resources/add.png
На SOF предлагают юзать Uri
MakeRelativeUri, но он не работает в Linux. А еще предлагают самописные фукнции разные. Проверил 2 штуки -- обе работали не во всех случаях. Нафарганил свою на скорую руку:
| Скрытый текст |
| public static string MakeRelativePath(string absoluteFilePath, string baseDirectory)
{
if (null == absoluteFilePath)
throw new ArgumentNullException(nameof(absoluteFilePath));
if (null == baseDirectory)
throw new ArgumentNullException(nameof(baseDirectory));
//absoluteFilePath = Path.GetFullPath(absoluteFilePath);
//baseDirectory = Path.GetFullPath(baseDirectory);
var directorySeparator = Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture);
var altDirectorySeparator = Path.AltDirectorySeparatorChar.ToString(CultureInfo.InvariantCulture);
string[] separators =
{
directorySeparator,
altDirectorySeparator
};
string[] absoluteFilePathParts = absoluteFilePath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
string[] baseDirectoryParts = baseDirectory.Split(separators, StringSplitOptions.RemoveEmptyEntries);
int length = Math.Min(absoluteFilePathParts.Length, baseDirectoryParts.Length);
int offset = 0;
for (int i = 0; i < length; i++)
{
if (absoluteFilePathParts[i].Equals(baseDirectoryParts[i], StringComparison.Ordinal))
offset++;
else break;
}
if (0 == offset)
{
if (!absoluteFilePath.StartsWith(directorySeparator)) // Linux
throw new ArgumentException("Paths do not have a common base!");
}
var relativePath = new StringBuilder();
for (int i = 0; i < baseDirectoryParts.Length - offset; i++)
{
relativePath.Append("..");
relativePath.Append(Path.DirectorySeparatorChar);
}
for (int i = offset; i < absoluteFilePathParts.Length - 1; i++)
{
relativePath.Append(absoluteFilePathParts[i]);
relativePath.Append(Path.DirectorySeparatorChar);
}
relativePath.Append(absoluteFilePathParts[absoluteFilePathParts.Length - 1]);
return relativePath.ToString();
}
|
| |
Кто может предложить вариант лучше или здесь увидит проблемы?
З.Ы.
Пока писал, уже увидел одну проблему -- сравнение папок идет с учетом регистра, что верно только для Linux, но не верно для Windows...
Здравствуйте, Shmj, Вы писали:
S>На SOF предлагают юзать Uri MakeRelativeUri, но он не работает в Linux.
.Net Core
Здравствуйте, Shmj, Вы писали:
S>Вроде тривиальная задача. Вот есть у вас путь к файлу, типа:
Не тривиальная. Особенно в венде.
А вот такой вопрос. Если пути содержат симлинки, что должна делать эта программа?
S>S> if (0 == offset)
S> {
S> if (!absoluteFilePath.StartsWith(directorySeparator)) // Linux
S> throw new ArgumentException("Paths do not have a common base!");
S> }
S>
Какой физический смысл этого действия? В линухе относительный путь всегда можно проложить, даже если оба пути расходятся в разные стороны, начиная от корня. В венде относительный путь нельзя проложить между путями, относящимися к разным томам.
S>Кто может предложить вариант лучше или здесь увидит проблемы?
Сил читать твой код у меня нет
В целом, я бы привел оба пути к абсолютному виду, проверил бы, на венде, что они относятся к одному и тому же тому, выделил бы общий префикс, if any, и с учетом этих знаний построил бы относительный путь.