C# 确定C中两个路径是否引用同一个文件的最佳方法#
在即将发布的Java7中,有一种方法可以检查两个文件对象是否是相同的文件引用 .NET framework中是否提供了类似的API 我已经在MSDN上搜索过了,但是没有任何东西能启发我 我希望它简单,但我不想比较的文件名,这将导致问题的硬/符号链接和不同风格的路径。(例如,C# 确定C中两个路径是否引用同一个文件的最佳方法#,c#,api,filesystems,C#,Api,Filesystems,在即将发布的Java7中,有一种方法可以检查两个文件对象是否是相同的文件引用 .NET framework中是否提供了类似的API 我已经在MSDN上搜索过了,但是没有任何东西能启发我 我希望它简单,但我不想比较的文件名,这将导致问题的硬/符号链接和不同风格的路径。(例如,\?\C:\,C:\) 我要做的就是防止重复的文件被拖放到我的链接列表中。编辑:注意,提到Win32 api中的函数,这正是您想要的,请检查并向上投票以获取更多信息 我认为你需要一个操作系统函数来提供你想要的信息,否则无论你
\?\C:\
,C:\
)
我要做的就是防止重复的文件被拖放到我的链接列表中。编辑:注意,提到Win32 api中的函数,这正是您想要的,请检查并向上投票以获取更多信息
我认为你需要一个操作系统函数来提供你想要的信息,否则无论你做什么都会有一些误报 例如,这些引用的是同一个文件吗
- \server\share\path\filename.txt
- \服务器\d$\temp\path\filename.txt
话虽如此,Path类中有一个方法可以做一些工作:,它至少会根据现有结构将路径扩展为长名称。之后,您只需比较字符串。不过,这并不是万无一失的,在我的示例中也不会处理上面的两个链接。您可以对这两个链接执行MD5编码并比较结果。效率不高,但比自己手动比较文件更容易
这是一篇关于的帖子。首先,我认为这很容易,但这不起作用:
string fileName1 = @"c:\vobp.log";
string fileName2 = @"c:\vobp.log".ToUpper();
FileInfo fileInfo1 = new FileInfo(fileName1);
FileInfo fileInfo2 = new FileInfo(fileName2);
if (!fileInfo1.Exists || !fileInfo2.Exists)
{
throw new Exception("one of the files does not exist");
}
if (fileInfo1.FullName == fileInfo2.FullName)
{
MessageBox.Show("equal");
}
也许这个图书馆有帮助。我自己没用过
编辑:在该网站上查看此示例:
//
// Path comparison
//
filePathAbsolute1 = new FilePathAbsolute(@"C:/Dir1\\File.txt");
filePathAbsolute2 = new FilePathAbsolute(@"C:\DIR1\FILE.TXT");
Debug.Assert(filePathAbsolute1.Equals(filePathAbsolute2));
Debug.Assert(filePathAbsolute1 == filePathAbsolute2);
据我所见,JDK7的做法是调用文件并比较dwVolumeSerialNumber、nFileIndexHigh和nFileIndexLow
根据MSDN:
您可以比较BY_HANDLE_FILE_信息结构中返回的VolumeSerialNumber和FileIndex成员,以确定两条路径是否映射到同一目标;例如,您可以比较两个文件路径并确定它们是否映射到同一目录
我不认为这个函数是由.NET包装的,所以您必须使用它
它可能适用于网络文件,也可能不适用于网络文件。根据MSDN:
根据操作系统的底层网络组件和连接到的服务器类型,GetFileInformationByHandle函数可能会失败,返回给定文件的部分信息或完整信息
快速测试表明,在使用SMB/Samba连接的Linux系统上,通过符号链接,它可以正常工作(值相同),但在使用指向同一文件的不同共享访问时,它无法检测到文件是否相同(FileIndex相同,但VolumeSerialNumber不同).答案:没有简单的方法可以比较字符串基路径来确定它们是否指向同一个文件 主要原因是看似不相关的路径可以指向与文件系统重定向(连接、符号链接等)完全相同的文件。比如说 “d:\temp\foo.txt” “c:\othertemp\foo.txt” 这些路径可能指向同一个文件。这种情况显然消除了任何字符串比较函数作为确定两条路径是否指向同一文件的基础 下一个级别是比较操作系统文件信息。打开两个路径的文件并比较句柄信息。在windows中,这可以通过GetFileInformationByHandle完成。卢西恩·维希克在这方面做得很好 不过,这种方法仍然存在一个问题。仅当执行检查的用户帐户能够打开这两个文件进行读取时,它才起作用。有许多项可以阻止用户打开一个或两个文件。包括但不限于
- 缺少足够的权限来创建文件
- 对文件路径中的目录缺乏足够的权限
- 在打开第一个文件和第二个文件之间发生的文件系统更改,如网络断开李>
当您开始研究所有这些问题时,您开始理解为什么Windows不提供一种方法来确定两条路径是否相同。这不是一个容易回答的问题 如果您需要反复比较相同的文件名,我建议您考虑将这些名称标准化 在Unix系统下,有一个函数可以使路径标准化。我认为如果你有一个复杂的路径,这通常是最好的选择。但是,在通过网络连接装载的卷上,它可能会失败 但是,基于realpath()方法,如果要支持多个卷(包括网络卷),可以编写自己的函数来检查路径中的每个目录名,如果它引用一个卷,然后确定两个路径中的卷引用是否相同。也就是说,装载点可能不同(即,目标卷上的路径可能不是该卷的根),因此解决过程中的所有问题并不是那么容易,但确实是可能的(否则它首先会如何工作?!) 一旦文件名正确标准化,一个简单的字符串比较就会给出正确的答案 如果不需要反复比较相同的文件名,Rasmus answer可能是最快的方法。下面是使用
GetFileInformationByHandle
实现的IsSameFile
:
NativeMethods.cs
public static class NativeMethods
{
[StructLayout(LayoutKind.Explicit)]
public struct BY_HANDLE_FILE_INFORMATION
{
[FieldOffset(0)]
public uint FileAttributes;
[FieldOffset(4)]
public FILETIME CreationTime;
[FieldOffset(12)]
public FILETIME LastAccessTime;
[FieldOffset(20)]
public FILETIME LastWriteTime;
[FieldOffset(28)]
public uint VolumeSerialNumber;
[FieldOffset(32)]
public uint FileSizeHigh;
[FieldOffset(36)]
public uint FileSizeLow;
[FieldOffset(40)]
public uint NumberOfLinks;
[FieldOffset(44)]
public uint FileIndexHigh;
[FieldOffset(48)]
public uint FileIndexLow;
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] FileAccess access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
IntPtr templateFile);
}
PathUtility.cs
public static bool IsSameFile(string path1, string path2)
{
using (SafeFileHandle sfh1 = NativeMethods.CreateFile(path1, FileAccess.Read, FileShare.ReadWrite,
IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
{
if (sfh1.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
using (SafeFileHandle sfh2 = NativeMethods.CreateFile(path2, FileAccess.Read, FileShare.ReadWrite,
IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
{
if (sfh2.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
NativeMethods.BY_HANDLE_FILE_INFORMATION fileInfo1;
bool result1 = NativeMethods.GetFileInformationByHandle(sfh1, out fileInfo1);
if (!result1)
throw new IOException(string.Format("GetFileInformationByHandle has failed on {0}", path1));
NativeMethods.BY_HANDLE_FILE_INFORMATION fileInfo2;
bool result2 = NativeMethods.GetFileInformationByHandle(sfh2, out fileInfo2);
if (!result2)
throw new IOException(string.Format("GetFileInformationByHandle has failed on {0}", path2));
return fileInfo1.VolumeSerialNumber == fileInfo2.VolumeSerialNumber
&& fileInfo1.FileIndexHigh == fileInfo2.FileIndexHigh
&& fileInfo1.FileIndexLow == fileInfo2.FileIndexLow;
}
}
}
文档中还说:“否则,此方法会检查两个fileref是否都位于同一个文件,并且根据实现的不同,可能需要打开或访问这两个文件。”实际上,我对seein非常感兴趣