如何确定多个文件路径格式指向同一物理位置

时间:2011-02-03 20:03:20

标签: c# path directory

  

可能重复:
  Best way to determine if two path reference to same file in C#

有几种方法可以指定目录位置。

例如:
\\计算机\ C $ \ ROOTPATH \子路径
\\ machineName \ shareName (分享指向subPath)
C:\ ROOTPATH \子路径
subPath (相对路径,如果已经在C:\ rootPath中

我需要确定所有这些路径彼此“相等”(实际上是硬盘上的物理位置相同)。

我有什么方法可以在C#中做到这一点吗?

6 个答案:

答案 0 :(得分:5)

正如Oded所说,在.Net中这很棘手。您可以通过将具有长随机生成的文件名的文件写入该位置来欺骗(取决于您的确切要求和权限等),然后查看您是否可以从其他位置看到它。有点破解,但我认为这是一个非常合理的测试,而不是依赖于解析映射驱动器等等。

对VB很多道歉 - 这就是我在这款小型上网本上的所有内容...... C#不会太差异......

用法例如

If sameLocation("\\machineName\c$\rootPath\subPath","\\machineName\shareName") Then...

Public Function sameLocation(ByVal sPath1 As String, ByVal sPath2 As String) As TriState
    Dim sFile As String = randomFilename()
    Dim sFullPath1 As String = sPath1 & "\" & sFile
    Dim sFullPath2 As String = sPath2 & "\" & sFile
    Dim bReturn As Boolean = False
    Try
        Dim fs As New FileStream(sFullPath1, FileMode.CreateNew)
        fs.Close()
    Catch ex As Exception
        Return TriState.UseDefault
    End Try

    Try
        bReturn = File.Exists(sFullPath2)
    Catch ex As Exception
        Return TriState.UseDefault
    End Try

    File.Delete(sFullPath1)
    Return bReturn
End Function

Public Function randomFilename() As String
    Dim r As New Random
    Randomize(My.Computer.Clock.TickCount)
    Dim sb As New StringBuilder
    Dim chars As Int16 = 100
    While chars > 0
        chars -= 1
        sb.Append(Chr(r.Next(26) + 65))
    End While
    Return sb.ToString
End Function

您可以添加更多安全性,即读取时间戳等...

答案 1 :(得分:4)

您需要使用GetFileInformationByHandle 在StackOverflow和answer帮助中查看此MSDN

这是我编写的一个使用目录的方法:

using System;
using System.Runtime.InteropServices;

namespace CompareByPath    
{    
  public static class DirectoryHelper  
  {
    // all user defined types copied from 
    // http://pinvoke.net/default.aspx/kernel32.CreateFile
    // http://pinvoke.net/default.aspx/kernel32.GetFileInformationByHandle
    // http://pinvoke.net/default.aspx/kernel32.CloseHandle

    public const short INVALID_HANDLE_VALUE = -1;

    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;
    }

    [Flags]
    public enum EFileAccess : uint
    {
      GenericRead = 0x80000000,
      GenericWrite = 0x40000000,
      GenericExecute = 0x20000000,
      GenericAll = 0x10000000
    }

    [Flags]
    public enum EFileShare : uint
    {
      None = 0x00000000,
      Read = 0x00000001,
      Write = 0x00000002,
      Delete = 0x00000004
    }

    [Flags]
    public enum EFileAttributes : uint
    {
      Readonly = 0x00000001,
      Hidden = 0x00000002,
      System = 0x00000004,
      Directory = 0x00000010,
      Archive = 0x00000020,
      Device = 0x00000040,
      Normal = 0x00000080,
      Temporary = 0x00000100,
      SparseFile = 0x00000200,
      ReparsePoint = 0x00000400,
      Compressed = 0x00000800,
      Offline = 0x00001000,
      NotContentIndexed = 0x00002000,
      Encrypted = 0x00004000,
      Write_Through = 0x80000000,
      Overlapped = 0x40000000,
      NoBuffering = 0x20000000,
      RandomAccess = 0x10000000,
      SequentialScan = 0x08000000,
      DeleteOnClose = 0x04000000,
      BackupSemantics = 0x02000000,
      PosixSemantics = 0x01000000,
      OpenReparsePoint = 0x00200000,
      OpenNoRecall = 0x00100000,
      FirstPipeInstance = 0x00080000
    }

    public enum ECreationDisposition : uint
    {
      New = 1,
      CreateAlways = 2,
      OpenExisting = 3,
      OpenAlways = 4,
      TruncateExisting = 5
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool GetFileInformationByHandle(IntPtr hFile, out        BY_HANDLE_FILE_INFORMATION lpFileInformation);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    public static bool CompareDirectories(string d1, string d2)
    {
      bool result = false;

      BY_HANDLE_FILE_INFORMATION info1;
      BY_HANDLE_FILE_INFORMATION info2;

      IntPtr fileHandle1 = CreateFile(d1, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
      if (fileHandle1.ToInt32() != INVALID_HANDLE_VALUE)
      {
        bool rc = GetFileInformationByHandle(fileHandle1, out info1);
        if ( rc )
        {
          IntPtr fileHandle2 = CreateFile(d2, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero);
          if (fileHandle2.ToInt32() != INVALID_HANDLE_VALUE)
          {
            rc = GetFileInformationByHandle(fileHandle2, out info2);
            if ( rc )
            {
              if (( info1.FileIndexHigh == info2.FileIndexHigh) &&
                  ( info1.FileIndexLow == info2.FileIndexLow) &&
                  ( info1.VolumeSerialNumber == info2.VolumeSerialNumber))
              {
                result = true;
              }
            }
          }

          CloseHandle(fileHandle2);
        }
      }

      CloseHandle(fileHandle1);

      return result;
    }
  }
}

答案 2 :(得分:2)

Windows中有许多别名方案:

  • 短名与长姓
  • 符号链接和硬链接
  • UNC名称与映射驱动器
  • 多个映射驱动器到同一网络路径
  • d:\ folder \ paths vs. \?\ d \ folder \ paths
  • NTFS挂载点

其中任何一个都可以出现在目录树的任何级别上。在.NET中,您可以解决其中一些问题,但不能解决其他问题。

作为一种围绕它的hackish方式,尝试锁定/解锁。将文件锁定为名称1,尝试打开名称2,确保它失败。然后解锁,再次尝试打开,确保成功。等等,有几次避免误报。与El Ronnoco的方式不同,这个方法可以检测路径级别和文件级别的别名。

在某些网络文件系统上,可能根本不支持锁定。此外,它可能需要一段时间 - 每次锁定/解锁/打开操作都是网络往返。

但这实际上取决于您的要求。如果您需要处理短/长名称,那就太过分了。

编辑:如果文件是只读文件或已被其他人打开,则会出现其他并发症。

答案 3 :(得分:0)

在.NET中没有本地方法可以做到这一点 - 它的级别太低了。

您可以使用Windows API来实现这一点(查看目录inode或其他标识符),但我不知道哪个API会公开它。

答案 4 :(得分:0)

AKAIK你甚至可以将同一个驱动器映射到许多驱动器号或子目录。网络共享目录也可以成倍增加,你永远不知道它们是否相同。

也许你可以添加信息,为什么你需要知道它。

答案 5 :(得分:0)

好问题,可能没有一个优雅的答案。

我能找到的最好的指向你的是net share命令行语句。如果可以通过编程方式捕获和摘要此命令生成的文本,则可以将网络共享1:1映射到其本地目标文件夹。然后,您可以在给定路径中查找这些共享映射的实例,并在执行基本字符串比较之前将其替换为等效的本地文件夹。