.NET框架中是否提供了类似的API?
我在MSDN上搜过了,但没有找到相关信息。
我想要一个简单的解决方案,但又不想通过文件名进行比较,因为这会导致硬链接/符号链接和不同路径风格(例如
\\?\C:\
、C:\
)出现问题。我的目标是防止重复的文件被拖放到我的链接列表中。
\\?\C:\
、C:\
)出现问题。我认为这个函数没有被.NET封装,因此您需要使用P/Invoke。您可以比较BY_HANDLE_FILE_INFORMATION结构中返回的VolumeSerialNumber和FileIndex成员,以确定两个路径是否映射到同一个目标;例如,您可以比较两个文件路径并确定它们是否映射到同一个目录。
它可能适用于网络文件,也可能不适用。根据MSDN:
取决于操作系统的底层网络组件和连接的服务器类型,GetFileInformationByHandle函数可能会失败、返回部分信息或完整信息。
一个快速测试显示,使用SMB/Samba连接的Linux系统上的符号链接可以正常工作(具有相同的值),但是当使用指向同一文件的不同共享访问文件时,它无法检测到文件是否相同(FileIndex相同,但VolumeSerialNumber不同)。
编辑:请注意,@Rasmus Faber在他的回答中提到了Win32 api中的GetFileInformationByHandle函数,它可以实现你想要的功能,请查看并点赞他的回答以获取更多信息。
我认为你需要一个操作系统函数来获得所需的信息,否则无论你做什么都会出现一些错误的结果。
例如,以下两个路径是否指向同一个文件?
我建议你先考虑不在列表中出现重复文件的重要性,然后尽力而为。
话虽如此,Path类中有一个方法可以完成部分工作:Path.GetFullPath,它至少可以将路径扩展为长名称,根据现有结构。之后,你只需比较字符串。但这并不是绝对可靠的,也无法处理我上面示例中的两个链接。
GetFileInformationByHandle
的C#实现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;
}
}
}
"d:\temp\foo.txt" "c:\othertemp\foo.txt"
这些路径有可能指向同一个文件。在这种情况下,任何字符串比较函数都无法作为确定两个路径是否指向同一文件的依据。一开始我认为这很容易, 但是不起作用:
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");
}
也许这个库可以帮助你 http://www.codeplex.com/FileDirectoryPath。我自己没有使用过。
编辑:在该网站上看到了这个例子:
//
// 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);
FileInfo
本身了吗? - nawfal你可以对两个文件进行MD5编码并比较结果。虽然不是很高效,但比手动比较文件要容易得多。
这里有一篇关于如何在C#中对字符串进行MD5编码的文章。