可能重复:
Best way to determine if two path reference to same file in C#
有几种方法可以指定目录位置。
例如:
的 \\计算机\ C $ \ ROOTPATH \子路径
\\ machineName \ shareName (分享指向subPath)
的 C:\ ROOTPATH \子路径
subPath (相对路径,如果已经在C:\ rootPath中
我需要确定所有这些路径彼此“相等”(实际上是硬盘上的物理位置相同)。
我有什么方法可以在C#中做到这一点吗?
答案 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中有许多别名方案:
其中任何一个都可以出现在目录树的任何级别上。在.NET中,您可以解决其中一些问题,但不能解决其他问题。
作为一种围绕它的hackish方式,尝试锁定/解锁。将文件锁定为名称1,尝试打开名称2,确保它失败。然后解锁,再次尝试打开,确保成功。等等,有几次避免误报。与El Ronnoco的方式不同,这个方法可以检测路径级别和文件级别的别名。
在某些网络文件系统上,可能根本不支持锁定。此外,它可能需要一段时间 - 每次锁定/解锁/打开操作都是网络往返。
但这实际上取决于您的要求。如果您需要处理短/长名称,那就太过分了。
编辑:如果文件是只读文件或已被其他人打开,则会出现其他并发症。
答案 3 :(得分:0)
在.NET中没有本地方法可以做到这一点 - 它的级别太低了。
您可以使用Windows API来实现这一点(查看目录inode或其他标识符),但我不知道哪个API会公开它。
答案 4 :(得分:0)
AKAIK你甚至可以将同一个驱动器映射到许多驱动器号或子目录。网络共享目录也可以成倍增加,你永远不知道它们是否相同。
也许你可以添加信息,为什么你需要知道它。
答案 5 :(得分:0)
好问题,可能没有一个优雅的答案。
我能找到的最好的指向你的是net share
命令行语句。如果可以通过编程方式捕获和摘要此命令生成的文本,则可以将网络共享1:1映射到其本地目标文件夹。然后,您可以在给定路径中查找这些共享映射的实例,并在执行基本字符串比较之前将其替换为等效的本地文件夹。