C #에서 (디렉터리) 경로를 어떻게 비교할 수 있습니까?
두 개의 DirectoryInfo
객체 가있는 경우 의미 론적 동등성을 위해 어떻게 비교할 수 있습니까? 예를 들어 다음 경로는 모두 다음과 같은 것으로 간주되어야합니다 C:\temp
.
C:\temp
C:\temp\
C:\temp\.
C:\temp\x\..\..\temp\.
다음은 같을 수도 있고 같지 않을 수도 있습니다 C:\temp
.
\temp
현재 작업 디렉토리가 드라이브에있는 경우C:\
temp
현재 작업 디렉토리가C:\
C:\temp.
C:\temp...\
현재 작업 디렉토리를 고려하는 것이 중요하다면 직접 알아낼 수 있으므로 그다지 중요하지 않습니다. 후행 점은 창에서 제거되므로 해당 경로는 실제로 동일해야하지만 유닉스에서는 제거되지 않으므로 모노에서는 다른 결과를 기대합니다.
대소 문자 구분은 선택 사항입니다. 경로는 존재하거나 존재하지 않을 수 있으며 사용자는 경로에 대한 권한을 가질 수도 있고 없을 수도 있습니다. I / O가 필요하지 않은 빠르고 강력한 방법을 선호하지만 (따라서 권한 검사가 필요하지 않음) 무언가가 구축 된 경우 -나도 "충분히 좋은"것으로도 행복 할 것입니다 ...
에서 이 답변 이 방법은 몇 가장자리 케이스를 처리 할 수 있습니다 :
public static string NormalizePath(string path)
{
return Path.GetFullPath(new Uri(path).LocalPath)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.ToUpperInvariant();
}
원래 답변에 자세한 내용이 있습니다. 다음과 같이 호출하십시오.
bool pathsEqual = NormalizePath(path1) == NormalizePath(path2);
파일 및 디렉토리 경로 모두에서 작동해야합니다.
GetFullPath
대소 문자 차이 ( Path.GetFullPath("test") != Path.GetFullPath("TEST")
)와 후행 슬래시를 제외하고는 작업을 수행하는 것 같습니다 . 따라서 다음 코드는 제대로 작동합니다.
String.Compare(
Path.GetFullPath(path1).TrimEnd('\\'),
Path.GetFullPath(path2).TrimEnd('\\'),
StringComparison.InvariantCultureIgnoreCase)
또는 다음으로 시작하려는 경우 DirectoryInfo
:
String.Compare(
dirinfo1.FullName.TrimEnd('\\'),
dirinfo2.FullName.TrimEnd('\\'),
StringComparison.InvariantCultureIgnoreCase)
.NET에서 경로를 구현하는 데는 몇 가지 단점이 있습니다. 그것에 대해 많은 불만이 있습니다. NDepend 의 창시자 인 Patrick Smacchia 는 일반적이고 복잡한 경로 작업을 처리 할 수 있는 오픈 소스 라이브러리를 게시했습니다 . 응용 프로그램의 경로에서 많은 비교 작업을 수행하는 경우이 라이브러리가 유용 할 수 있습니다.
나는 이것이 오래된 게시물이라는 것을 알고 있지만 모든 답변은 궁극적으로 두 이름의 텍스트 비교를 기반으로합니다. 동일한 파일 객체를 참조 할 수있는 무수한 방법을 고려하는 두 개의 "정규화 된"이름을 얻으려는 시도는 거의 불가능합니다. 교차점, 심볼릭 링크, 네트워크 파일 공유 (다른 방식으로 동일한 파일 객체 참조) 등과 같은 문제가 있습니다 . 실제로 Igor Korkhov의 경우를 제외하고 위의 모든 답변은 절대적으로 잘못된 결과를 제공합니다. 특정 상황 (예 : 접합, 기호 링크, 디렉토리 링크 등)
이 질문은 솔루션에 I / O가 필요하지 않다고 특별히 요청했지만 네트워크 경로를 처리하려는 경우 반드시 IO를 수행해야합니다. 로컬 경로 문자열에서 확인할 수없는 경우가 있습니다. 조작, 두 파일 참조가 동일한 실제 파일을 참조하는지 여부. (이는 다음과 같이 쉽게 이해할 수 있습니다. 파일 서버에 공유 하위 트리 내 어딘가에 Windows 디렉토리 접합이 있다고 가정합니다.이 경우 파일은 직접 또는 접합을 통해 참조 될 수 있습니다. 그러나 접합은 파일 서버에 있습니다. 따라서 클라이언트가 순전히 로컬 정보를 통해 두 참조 파일 이름이 동일한 실제 파일을 참조하는지 확인하는 것은 불가능합니다. 정보는 단순히 클라이언트가 로컬로 사용할 수 없습니다.
다음 솔루션은 매우 최소한이지만 일부 IO를 수행하지만 두 파일 시스템 참조가 의미 상 동일한 지, 즉 동일한 파일 객체를 참조하는지 정확하게 결정합니다. (파일 사양이 유효한 파일 객체를 참조하지 않는 경우 모든 베팅이 해제됩니다) :
public static bool AreFileSystemObjectsEqual(string dirName1, string dirName2)
{
//Optimization: if strings are equal, don't bother with the IO
bool bRet = string.Equals(dirName1, dirName2, StringComparison.OrdinalIgnoreCase);
if (!bRet)
{
//NOTE: we cannot lift the call to GetFileHandle out of this routine, because we _must_
// have both file handles open simultaneously in order for the objectFileInfo comparison
// to be guaranteed as valid.
using (SafeFileHandle directoryHandle1 = GetFileHandle(dirName1), directoryHandle2 = GetFileHandle(dirName2))
{
BY_HANDLE_FILE_INFORMATION? objectFileInfo1 = GetFileInfo(directoryHandle1);
BY_HANDLE_FILE_INFORMATION? objectFileInfo2 = GetFileInfo(directoryHandle2);
bRet = objectFileInfo1 != null
&& objectFileInfo2 != null
&& (objectFileInfo1.Value.FileIndexHigh == objectFileInfo2.Value.FileIndexHigh)
&& (objectFileInfo1.Value.FileIndexLow == objectFileInfo2.Value.FileIndexLow)
&& (objectFileInfo1.Value.VolumeSerialNumber == objectFileInfo2.Value.VolumeSerialNumber);
}
}
return bRet;
}
이에 대한 아이디어는 내가 SuperUser에 게시 한 유사한 질문에 대한 Warren Stevens의 답변에서 나왔습니다. https://superuser.com/a/881966/241981
P / Invoking GetFinalPathNameByHandle () 이 가장 신뢰할 수있는 솔루션 인 것 같습니다.
UPD : 죄송합니다. I / O를 사용하지 않으려는 귀하의 욕구를 고려하지 않았습니다.
System.IO.Path.GetFullPath(pathA).Equals(System.IO.Path.GetFullPath(PathB));
Microsoft는 위의 답변만큼 유용하지는 않지만 유사한 방법을 구현했습니다.
- PathUtil.ArePathsEqual 메서드 (단지
return string.Equals(path1, path2, StringComparison.OrdinalIgnoreCase);
) - PathUtil.Normalize 메서드
- PathUtil.NormalizePath 메서드 (단지
return PathUtil.Normalize(path);
)
"이름"속성은 동일합니다. 갖다:
DirectoryInfo dir1 = new DirectoryInfo("C:\\Scratch");
DirectoryInfo dir2 = new DirectoryInfo("C:\\Scratch\\");
DirectoryInfo dir3 = new DirectoryInfo("C:\\Scratch\\4760");
DirectoryInfo dir4 = new DirectoryInfo("C:\\Scratch\\4760\\..\\");
dir1.Name == dir2.Name and dir2.Name == dir4.Name
(이 경우 "스크래치". dir3 == "4760".) FullName 속성 만 다릅니다.
전체 경로가 동일한 지 확인하기 위해 두 개의 DirectoryInfo 클래스가 지정된 각 부모의 Name 속성을 검사하는 재귀 메서드를 수행 할 수 있습니다.
편집 : 이것이 귀하의 상황에서 작동합니까? 콘솔 응용 프로그램을 만들고 전체 Program.cs 파일에 붙여 넣습니다. AreEquals () 함수에 두 개의 DirectoryInfo 개체를 제공하면 같은 디렉터리이면 True를 반환합니다. 원하는 경우이 AreEquals()
메서드를 DirectoryInfo의 확장 메서드 로 조정할 수 있습니다.myDirectoryInfo.IsEquals(myOtherDirectoryInfo);
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AreEqual(
new DirectoryInfo("C:\\Scratch"),
new DirectoryInfo("C:\\Scratch\\")));
Console.WriteLine(AreEqual(
new DirectoryInfo("C:\\Windows\\Microsoft.NET\\Framework"),
new DirectoryInfo("C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\1033\\..\\..")));
Console.WriteLine(AreEqual(
new DirectoryInfo("C:\\Scratch\\"),
new DirectoryInfo("C:\\Scratch\\4760\\..\\..")));
Console.WriteLine("Press ENTER to continue");
Console.ReadLine();
}
private static bool AreEqual(DirectoryInfo dir1, DirectoryInfo dir2)
{
DirectoryInfo parent1 = dir1;
DirectoryInfo parent2 = dir2;
/* Build a list of parents */
List<string> folder1Parents = new List<string>();
List<string> folder2Parents = new List<string>();
while (parent1 != null)
{
folder1Parents.Add(parent1.Name);
parent1 = parent1.Parent;
}
while (parent2 != null)
{
folder2Parents.Add(parent2.Name);
parent2 = parent2.Parent;
}
/* Now compare the lists */
if (folder1Parents.Count != folder2Parents.Count)
{
// Cannot be the same - different number of parents
return false;
}
bool equal = true;
for (int i = 0; i < folder1Parents.Count && i < folder2Parents.Count; i++)
{
equal &= folder1Parents[i] == folder2Parents[i];
}
return equal;
}
}
}
Node.js의 미니 매치 포트 인 미니 매치를 사용할 수 있습니다.
var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });
if (mm.IsMatch(somePath))
{
// The path matches! Do some cool stuff!
}
var matchingPaths = mm.Filter(allPaths);
이유를 참조AllowWindowsPaths = true
옵션이 필요합니다 :
Windows 스타일 경로에서 Minimatch의 구문은 Linux 스타일 경로 용으로 설계되었습니다 (슬래시 만 사용). 특히 백 슬래시를 이스케이프 문자로 사용하므로 단순히 Windows 스타일 경로를 허용 할 수 없습니다. 내 C # 버전은이 동작을 유지합니다.
이를 억제하고 백 슬래시와 슬래시를 경로 구분 기호 (패턴 또는 입력)로 허용하려면 다음
AllowWindowsPaths
옵션을 설정하십시오 .var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });
이 옵션을 전달하면 이스케이프 문자가 완전히 비활성화됩니다.
Nuget : http://www.nuget.org/packages/Minimatch/
GitHub : https://github.com/SLaks/Minimatch
bool equals = myDirectoryInfo1.FullName == myDirectoryInfo2.FullName;
?
using System;
using System.Collections.Generic;
using System.Text;
namespace EventAnalysis.IComparerImplementation
{
public sealed class FSChangeElemComparerByPath : IComparer<FSChangeElem>
{
public int Compare(FSChangeElem firstPath, FSChangeElem secondPath)
{
return firstPath.strObjectPath == null ?
(secondPath.strObjectPath == null ? 0 : -1) :
(secondPath.strObjectPath == null ? 1 : ComparerWrap(firstPath.strObjectPath, secondPath.strObjectPath));
}
private int ComparerWrap(string stringA, string stringB)
{
int length = 0;
int start = 0;
List<string> valueA = new List<string>();
List<string> valueB = new List<string>();
ListInit(ref valueA, stringA);
ListInit(ref valueB, stringB);
if (valueA.Count != valueB.Count)
{
length = (valueA.Count > valueB.Count)
? valueA.Count : valueB.Count;
if (valueA.Count != length)
{
for (int i = 0; i < length - valueA.Count; i++)
{
valueA.Add(string.Empty);
}
}
else
{
for (int i = 0; i < length - valueB.Count; i++)
{
valueB.Add(string.Empty);
}
}
}
else
length = valueA.Count;
return RecursiveComparing(valueA, valueB, length, start);
}
private void ListInit(ref List<string> stringCollection, string stringToList)
{
foreach (string s in stringToList.Remove(0, 2).Split('\\'))
{
stringCollection.Add(s);
}
}
private int RecursiveComparing(List<string> valueA, List<string> valueB, int length, int start)
{
int result = 0;
if (start != length)
{
if (valueA[start] == valueB[start])
{
result = RecursiveComparing(valueA, valueB, length, ++start);
}
else
{
result = String.Compare(valueA[start], valueB[start]);
}
}
else
return 0;
return result;
}
}
}
bool Equals(string path1, string path2)
{
return new Uri(path1) == new Uri(path2);
}
Uri 생성자는 경로를 정규화합니다.
참고 URL : https://stackoverflow.com/questions/2281531/how-can-i-compare-directory-paths-in-c
'Programing' 카테고리의 다른 글
Android에서 외부 SD 카드에 쓰는 보편적 인 방법 (0) | 2020.11.05 |
---|---|
인터페이스를 사용하는 이유는 무엇입니까? (0) | 2020.11.05 |
CSS 페이지 나누기를 적용하여 행이 많은 표를 인쇄하는 방법은 무엇입니까? (0) | 2020.11.04 |
다른 쉘 스크립트에서 쉘 스크립트의 함수를 호출 할 수 있습니까? (0) | 2020.11.04 |
HashMap 값이 목록에 캐스팅되지 않는 이유는 무엇입니까? (0) | 2020.11.04 |