programing

현재 작업 디렉토리에 상대적인 경로를 얻습니까?

nasanasas 2020. 10. 23. 07:57
반응형

현재 작업 디렉토리에 상대적인 경로를 얻습니까?


이 질문에 이미 답변이 있습니다.

명령 줄에 지정된 파일에 대해 일부 처리를 수행하기 위해 콘솔 유틸리티를 작성하고 있지만 Google / Stack Overflow를 통해 해결할 수없는 문제가 발생했습니다. 드라이브 문자를 포함한 전체 경로가 지정된 경우 해당 경로를 현재 작업 디렉토리에 상대적으로 다시 포맷하려면 어떻게해야합니까?

VirtualPathUtility.MakeRelative 함수와 비슷한 것이있을 것입니다. 그러나 만약 있다면 그것은 저를 피할 수 있습니다.


슬래시가 바뀌어도 괜찮다면 다음과 같이 사용할 수 있습니다 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;
}

이 코드는 아마도 방탄이 아니지만 이것이 제가 생각 해낸 것입니다. 좀 더 견고합니다. 두 개의 경로를 사용하고 경로 A에 상대적인 경로 B를 반환합니다.

예:

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"

여기에있는 다른 답변 덕분에 몇 가지 실험 후에 매우 유용한 확장 방법을 만들었습니다.

public static string GetRelativePathFrom(this FileSystemInfo to, FileSystemInfo from)
{
    return from.GetRelativePathTo(to);
}

public static string GetRelativePathTo(this FileSystemInfo from, FileSystemInfo to)
{
    Func<FileSystemInfo, string> getPath = fsi =>
    {
        var d = fsi as DirectoryInfo;
        return d == null ? fsi.FullName : d.FullName.TrimEnd('\\') + "\\";
    };

    var fromPath = getPath(from);
    var toPath = getPath(to);

    var fromUri = new Uri(fromPath);
    var toUri = new Uri(toPath);

    var relativeUri = fromUri.MakeRelativeUri(toUri);
    var relativePath = Uri.UnescapeDataString(relativeUri.ToString());

    return relativePath.Replace('/', Path.DirectorySeparatorChar);
}

Important points:

  • Use FileInfo and DirectoryInfo as method parameters so there is no ambiguity as to what is being worked with. Uri.MakeRelativeUri expects directories to end with a trailing slash.
  • DirectoryInfo.FullName doesn't normalize the trailing slash. It outputs whatever path was used in the constructor. This extension method takes care of that for you.

There is also a way to do this with some restrictions. This is the code from the article:

public string RelativePath(string absPath, string relTo)
    {
        string[] absDirs = absPath.Split('\\');
        string[] relDirs = relTo.Split('\\');
        // Get the shortest of the two paths 
        int len = absDirs.Length < relDirs.Length ? absDirs.Length : relDirs.Length;
        // Use to determine where in the loop we exited 
        int lastCommonRoot = -1; int index;
        // Find common root 
        for (index = 0; index < len; index++)
        {
            if (absDirs[index] == relDirs[index])
                lastCommonRoot = index;
            else break;
        }
        // If we didn't find a common prefix then throw 
        if (lastCommonRoot == -1)
        {
            throw new ArgumentException("Paths do not have a common base");
        }
        // Build up the relative path 
        StringBuilder relativePath = new StringBuilder();
        // Add on the .. 
        for (index = lastCommonRoot + 1; index < absDirs.Length; index++)
        {
            if (absDirs[index].Length > 0) relativePath.Append("..\\");
        }
        // Add on the folders 
        for (index = lastCommonRoot + 1; index < relDirs.Length - 1; index++)
        {
            relativePath.Append(relDirs[index] + "\\");
        }
        relativePath.Append(relDirs[relDirs.Length - 1]);
        return relativePath.ToString();
    }

When executing this piece of code:

string path1 = @"C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir1"; 
string path2 = @"C:\Inetpub\wwwroot\Project1\Master\Dev\SubDir2\SubDirIWant";

System.Console.WriteLine (RelativePath(path1, path2));
System.Console.WriteLine (RelativePath(path2, path1));

it prints out:

..\SubDir2\SubDirIWant
..\..\SubDir1

참고URL : https://stackoverflow.com/questions/703281/getting-path-relative-to-the-current-working-directory

반응형