Функция для получения относительного пути
От: Shmj Ниоткуда  
Дата: 06.09.17 21:17
Оценка:
Вроде тривиальная задача. Вот есть у вас путь к файлу, типа:

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...
Отредактировано 06.09.2017 21:39 Shmj . Предыдущая версия .
Re: Функция для получения относительного пути
От: vorona  
Дата: 07.09.17 03:36
Оценка:
Здравствуйте, Shmj, Вы писали:

S>На SOF предлагают юзать Uri MakeRelativeUri, но он не работает в Linux.

.Net Core
Re: Функция для получения относительного пути
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.09.17 11:12
Оценка:
Здравствуйте, 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, и с учетом этих знаний построил бы относительный путь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.