在即将发布的Java7中,有new API来检查两个文件对象是否是同一个文件引用。
.NET框架中是否提供了类似的API?
我通过MSDN搜索它,但没有任何启发我。
我希望它很简单,但我不想通过文件名进行比较,这将导致硬/符号链接和不同路径样式的问题。 (例如\\?\C:\
,C:\
)。
我要做的就是阻止重复文件被拖放到我的链接列表中。
答案 0 :(得分:33)
据我所知,(1) (2) (3) (4),JDK7的工作方式是在文件上调用GetFileInformationByHandle并比较dwVolumeSerialNumber ,nFileIndexHigh和nFileIndexLow。
每个MSDN:
您可以比较BY_HANDLE_FILE_INFORMATION结构中返回的VolumeSerialNumber和FileIndex成员,以确定两条路径是否映射到同一目标;例如,您可以比较两个文件路径并确定它们是否映射到同一目录。
我不认为这个函数是由.NET包装的,所以你必须使用P/Invoke。
它可能适用于网络文件,也可能不适用。根据MSDN:
根据操作系统的基础网络组件和连接到的服务器类型,GetFileInformationByHandle函数可能会失败,返回部分信息或给定文件的完整信息。
快速测试显示它在使用SMB / Samba连接的Linux系统上使用符号链接按预期工作(相同值),但是当使用指向不同的共享访问时,它无法检测到文件是否相同相同的文件(FileIndex是相同的,但VolumeSerialNumber不同)。
答案 1 :(得分:7)
修改:请注意,@Rasmus Faber提到了Win32 api中的GetFileInformationByHandle功能,这可以满足您的需求,检查并提升他的answer以获取更多信息信息。
我认为您需要一个操作系统功能来提供您想要的信息,否则无论您做什么都会产生一些漏报。
例如,这些是否指的是同一个文件?
我会检查你的列表中没有重复文件的重要性,然后尽一切努力。
话虽如此,Path类中有一个方法可以完成一些工作:Path.GetFullPath,根据现有结构,它至少会扩展到长名称的路径。之后你只需比较字符串。虽然它不会万无一失,并且在我的例子中不会处理上面的两个链接。
答案 2 :(得分:2)
答案:没有万无一失的方法可以与字符串基本路径进行比较,以确定它们是否指向同一个文件。
主要原因是看似无关的路径可以指向文件系统重定向(联结,符号链接等)完全相同的文件。例如
“d:\ TEMP \ foo.txt的” “c:\ othertemp \ foo.txt”
这些路径可能指向同一个文件。这种情况明确地消除了任何字符串比较功能,作为确定两个路径是否指向同一文件的基础。
下一级是比较OS文件信息。打开两个路径的文件并比较句柄信息。在Windows中,可以使用GetFileInformationByHandle完成。 Lucian Wischik在这里就这个问题做了很好的post。
但这种方法仍然存在问题。仅当执行检查的用户帐户能够打开两个文件进行阅读时,它才有效。有许多项可以阻止用户打开一个或两个文件。包括但不限于......
当您开始查看所有这些问题时,您就会开始理解为什么Windows不提供确定两条路径是否相同的方法。这不是一个简单/可能的问题。
答案 3 :(得分:2)
以下是使用IsSameFile
的{{1}}的C#实现:
NativeMethods.cs
GetFileInformationByHandle
PathUtility.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);
}
答案 4 :(得分:1)
首先我认为这很容易,但不工作:
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);
答案 5 :(得分:0)
如果您需要反复比较相同的文件名,我建议您考虑对这些名称进行元素化。
在Unix系统下,有realpath()功能可以使您的路径成为可能。我认为如果你有一个复杂的路径,这通常是最好的选择。但是,通过网络连接挂载的卷可能会失败。
但是,基于realpath()方法,如果要支持包括网络卷在内的多个卷,可以编写自己的函数来检查路径中的每个目录名称,如果它引用了卷,则确定是否为卷引用两条路径都是一样的。这就是说,挂载点可能不同(即目标卷上的路径可能不是该卷的根),因此沿途解决所有问题并不容易,但它确实是可能的(否则如何它会起作用吗?!)
一旦文件名正确地进行了内省化,简单的字符串比较就会给出正确答案。
如果您不需要一遍又一遍地比较相同的文件名,那么Rasmus答案可能是最快的方法。
答案 6 :(得分:-4)
您始终可以对两者执行MD5编码并比较结果。效率不高,但比手动比较文件更容易。
以下是how to MD5 a string in C#上的帖子。