Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何比较C#中的(目录)路径?_C#_.net_Path_Filesystems - Fatal编程技术网

如何比较C#中的(目录)路径?

如何比较C#中的(目录)路径?,c#,.net,path,filesystems,C#,.net,Path,Filesystems,如果我有两个DirectoryInfo对象,如何比较它们的语义平等性?例如,以下路径应全部视为等于C:\temp: C:\temp C:\temp\ C:\temp\. C:\temp\x\..\temp\. 以下各项可能等于也可能不等于C:\temp: \temp如果当前工作目录位于驱动器C:\ temp如果当前工作目录是C:\ C:\temp. C:\temp…\ 如果考虑当前的工作目录是很重要的,我可以自己解决这个问题,所以这并不重要。尾随点在windows中被剥离,所以这些路径实

如果我有两个
DirectoryInfo
对象,如何比较它们的语义平等性?例如,以下路径应全部视为等于
C:\temp

  • C:\temp
  • C:\temp\
  • C:\temp\.
  • C:\temp\x\..\temp\.
以下各项可能等于也可能不等于C:\temp:

  • \temp
    如果当前工作目录位于驱动器
    C:\
  • temp
    如果当前工作目录是
    C:\
  • C:\temp.
  • C:\temp…\
如果考虑当前的工作目录是很重要的,我可以自己解决这个问题,所以这并不重要。尾随点在windows中被剥离,所以这些路径实际上应该是相等的——但在unix中它们并没有被剥离,所以在mono下我希望得到其他结果

区分大小写是可选的。路径可能存在也可能不存在,用户可能有权限也可能没有权限——我更喜欢不需要任何I/O(因此无需权限检查)的快速健壮方法,但如果有内置的东西,我也会对任何“足够好”的东西感到满意

我意识到,如果没有I/O,就不可能确定某个中间存储层是否碰巧将同一个存储映射到同一个文件(即使使用I/O,当事情变得足够混乱时,也不可能)。但是,不管底层的文件系统是什么,至少应该能够肯定地标识出等价的路径,即在给定类型的所有可能的文件系统上解析为相同文件(如果存在)的路径。这有时很有用的原因是(A)因为我当然想在进行I/O之前首先检查这一点,(B)I/O有时会触发有问题的副作用,(C)各种其他软件组件有时会损坏提供的路径,能够以一种对最常见的等效路径转换不敏感的方式进行比较是很有帮助的,最后(D)为了准备部署,事先做一些健全性检查是很有用的,但这些检查发生在要部署到系统上的文件甚至可以访问之前

bool equals = myDirectoryInfo1.FullName == myDirectoryInfo2.FullName;

似乎p/调用将是最可靠的解决方案

UPD:Oops,我没有考虑到您不使用任何I/O的愿望,“Name”属性是相等的。采取:

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和dir2.Name==dir4.Name
(本例中为“Scratch”。dir3==4760)。)只有全名属性不同

在给定两个DirectoryInfo类的情况下,您可以使用递归方法检查每个父类的名称属性,以确保完整路径相同

编辑:这适合您的情况吗?创建控制台应用程序并将其粘贴到整个Program.cs文件上。为AreEquals()函数提供两个DirectoryInfo对象,如果它们是同一个目录,则返回True。如果愿意,您可以将这个
AreEquals()
方法调整为DirectoryInfo上的扩展方法,这样您就可以执行
myDirectoryInfo.IsEquals(myOtherDirectoryInfo)

使用系统;
使用系统诊断;
使用System.IO;
使用System.Collections.Generic;
命名空间控制台应用程序3
{
班级计划
{
静态void Main(字符串[]参数)
{
控制台写入线(AREEQUALE)(
新目录信息(“C:\\Scratch”),
新目录信息(“C:\\Scratch\\”);
控制台写入线(AREEQUALE)(
新目录信息(“C:\\Windows\\Microsoft.NET\\Framework”),
新目录信息(“C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\1033\\\”);
控制台写入线(AREEQUALE)(
新目录信息(“C:\\Scratch\\”,
新目录信息(“C:\\Scratch\\4760\\\”);
Console.WriteLine(“按ENTER键继续”);
Console.ReadLine();
}
私有静态布尔值相等(DirectoryInfo dir1,DirectoryInfo dir2)
{
DirectoryInfo parent1=dir1;
DirectoryInfo parent2=dir2;
/*建立一个家长列表*/
List folder1Parents=新列表();
List folder2Parents=新列表();
while(parent1!=null)
{
folder1Parents.Add(parent1.Name);
parent1=parent1.parent1;
}
while(parent2!=null)
{
folder2Parents.Add(parent2.Name);
parent2=parent2.parent2;
}
/*现在比较一下列表*/
if(folder1Parents.Count!=folder2Parents.Count)
{
//不能相同-不同数量的家长
返回false;
}
布尔等于真;
for(int i=0;i
在.NET中实现路径有一些不足之处。对此有很多抱怨,NDepend的创始人发表了一篇文章。如果您在应用程序中对路径执行大量比较操作,此库可能会对您有用。

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)
使用系统;
使用System.Collections.Generic;
使用系统文本;
命名空间EventAnalysis.IComparerImplementation
{
公共密封类FSChangeElemComparerByPath:IComparer
{
公共国际公司
String.Compare(
    Path.GetFullPath(path1).TrimEnd('\\'),
    Path.GetFullPath(path2).TrimEnd('\\'), 
    StringComparison.InvariantCultureIgnoreCase)
String.Compare(
    dirinfo1.FullName.TrimEnd('\\'),
    dirinfo2.FullName.TrimEnd('\\'), 
    StringComparison.InvariantCultureIgnoreCase)
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;
        }
    }
}
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);
bool Equals(string path1, string path2)
{
    return new Uri(path1) == new Uri(path2);
}
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);
var mm = new Minimatcher(searchPattern, new Options { AllowWindowsPaths = true });
public static bool AreDirsEqual(string dirName1, string dirName2, bool resolveJunctionaAndNetworkPaths = true)
{
    if (string.IsNullOrEmpty(dirName1) || string.IsNullOrEmpty(dirName2))
        return dirName1==dirName2;
    dirName1 = NormalizePath(dirName1); //assume NormalizePath normalizes/fixes case and path separators to Path.DirectorySeparatorChar
    dirName2 = NormalizePath(dirName2);
    int i1 = dirName1.Length;
    int i2 = dirName2.Length;
    do
    {
        --i1; --i2;
        if (i1 < 0 || i2 < 0)
            return i1 < 0 && i2 < 0;
    } while (dirName1[i1] == dirName2[i2]);//If you want to deal with international character sets, i.e. if NormalixePath does not fix case, this comparison must be tweaked
    if( !resolveJunctionaAndNetworkPaths )
        return false;
    for(++i1, ++i2; i1 < dirName1.Length; ++i1, ++i2)
    {
        if (dirName1[i1] == Path.DirectorySeparatorChar)
        {
            dirName1 = dirName1.Substring(0, i1);
            dirName2 = dirName1.Substring(0, i2);
            break;
        }
    }
    return AreFileSystemObjectsEqual(dirName1, dirName2);
}

public static bool AreFileSystemObjectsEqual(string dirName1, string dirName2)
{
    //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);
        return objectFileInfo1 != null
                && objectFileInfo2 != null
                && (objectFileInfo1.Value.FileIndexHigh == objectFileInfo2.Value.FileIndexHigh)
                && (objectFileInfo1.Value.FileIndexLow == objectFileInfo2.Value.FileIndexLow)
                && (objectFileInfo1.Value.VolumeSerialNumber == objectFileInfo2.Value.VolumeSerialNumber);
    }
}

static SafeFileHandle GetFileHandle(string dirName)
{
    const int FILE_ACCESS_NEITHER = 0;
    //const int FILE_SHARE_READ = 1;
    //const int FILE_SHARE_WRITE = 2;
    //const int FILE_SHARE_DELETE = 4;
    const int FILE_SHARE_ANY = 7;//FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
    const int CREATION_DISPOSITION_OPEN_EXISTING = 3;
    const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
    return CreateFile(dirName, FILE_ACCESS_NEITHER, FILE_SHARE_ANY, System.IntPtr.Zero, CREATION_DISPOSITION_OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero);
}


static BY_HANDLE_FILE_INFORMATION? GetFileInfo(SafeFileHandle directoryHandle)
{
    BY_HANDLE_FILE_INFORMATION objectFileInfo;
    if ((directoryHandle == null) || (!GetFileInformationByHandle(directoryHandle.DangerousGetHandle(), out objectFileInfo)))
    {
        return null;
    }
    return objectFileInfo;
}

[DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
 IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);

[StructLayout(LayoutKind.Sequential)]
public struct BY_HANDLE_FILE_INFORMATION
{
    public uint FileAttributes;
    public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
    public uint VolumeSerialNumber;
    public uint FileSizeHigh;
    public uint FileSizeLow;
    public uint NumberOfLinks;
    public uint FileIndexHigh;
    public uint FileIndexLow;
};
 public bool PathEquals(string Path1, string Path2)
 {
     FileInfo f1 = new FileInfo(Path1.Trim('\\','/','.'));
     FileInfo f2 = new FileInfo(Path2.Trim('\\', '/','.'));
     if(f1.Name.ToLower() == f2.Name.ToLower())
     {
         return DirectoryEquals(f1.Directory, f2.Directory);
     }
     else
     {
         return false;
     }
}

public bool DirectoryEquals(DirectoryInfo d1, DirectoryInfo d2)
{
    if(d1.Name.ToLower() == d2.Name.ToLower())
    {
        if((d1.Parent != null) && (d2.Parent != null))
        {
            return DirectoryEquals(d1.Parent, d2.Parent);
        }
        else
        {
            return true;//C:\Temp1\Temp2 equals \Temp1\Temp2
            //return (d1.Parent == null) && (d2.Parent == null);//C:\Temp1\Temp2 does not equal \Temp1\Temp2
        }
    }
    else
    {
        return false;
    }
}