Windows中唯一的文件标识符
是否有办法唯一标识文件的生命周期(可能是目录),无论移动,重命名和内容修改? (Windows 2000和更高版本)。 制作一个文件的副本应该给副本它自己的唯一标识符。
我的应用程序将各种元数据与单个文件关联起来。 如果文件被修改,重命名或移动,则能够自动检测和更新文件关联是有用的。
FileSystemWatcher可以提供通知这些改变的事件,但是如果很多文件系统事件发生的话,FileSystemWatcher会使用一个容易填充的内存缓冲区(并且事件丢失)。
哈希是没有用的,因为文件的内容可以改变,所以哈希将改变。
我曾经想过使用文件创builddate,但是有一些情况下这不是唯一的(即多个文件被复制时)。
我也听说过NTFS文件SID(安全ID?),但我不知道这是否会做我正在寻找。
有任何想法吗?
如果你调用GetFileInformationByHandle ,你会得到一个BY_HANDLE_FILE_INFORMATION.nFileIndexHigh / Low的文件ID。 此索引在卷中是唯一的,即使移动文件(在卷中)或重命名该索引也是如此。
如果您可以假定使用NTFS,则可能还需要考虑使用备用数据stream来存储元数据。
以下是返回唯一文件索引的示例代码。
ApproachA()就是我经过一番研究后想出来的。 ApproachB()感谢Mattias和Rubens提供的链接中的信息。 给定一个特定的文件,这两种方法返回相同的文件索引(在我的基本testing)。
MSDN的一些注意事项:
对文件ID的支持是文件系统特定的。 文件ID不能保证是唯一的,因为文件系统可以自由地重用它们。 在某些情况下,文件的文件ID可能随时间而改变。
在FAT文件系统中,文件ID由包含目录的第一个簇和文件条目目录中的字节偏移量生成。 一些碎片整理产品更改此字节偏移量。 (Windows内置碎片整理不)。因此,FAT文件ID可以随时间变化。 在FAT文件系统中重命名文件也可以更改文件ID,但前提是新文件名比旧文件名更长。
在NTFS文件系统中,文件保持相同的文件ID直到被删除 。 您可以用另一个文件replace一个文件,而不必使用ReplaceFile函数更改文件ID。 但是,replace文件的文件ID,而不是被replace的文件,被保留为结果文件的文件ID。
上面第一个粗体的评论让我担心。 目前还不清楚这个陈述是否仅适用于FAT,这似乎与第二个粗体文本相矛盾。 我想进一步的testing是唯一确定的方法。
[更新:在我testing文件索引/ id时,文件从一个内部NTFS硬盘驱动器移动到另一个内部NTFS硬盘驱动器更改。
public class WinAPI { [DllImport("ntdll.dll", SetLastError = true)] public static extern IntPtr NtQueryInformationFile(IntPtr fileHandle, ref IO_STATUS_BLOCK IoStatusBlock, IntPtr pInfoBlock, uint length, FILE_INFORMATION_CLASS fileInformation); public struct IO_STATUS_BLOCK { uint status; ulong information; } public struct _FILE_INTERNAL_INFORMATION { public ulong IndexNumber; } // Abbreviated, there are more values than shown public enum FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, // 1 FileFullDirectoryInformation, // 2 FileBothDirectoryInformation, // 3 FileBasicInformation, // 4 FileStandardInformation, // 5 FileInternalInformation // 6 } [DllImport("kernel32.dll", SetLastError = true)] public static extern bool GetFileInformationByHandle(IntPtr hFile,out BY_HANDLE_FILE_INFORMATION lpFileInformation); public struct BY_HANDLE_FILE_INFORMATION { public uint FileAttributes; public FILETIME CreationTime; public FILETIME LastAccessTime; public FILETIME LastWriteTime; public uint VolumeSerialNumber; public uint FileSizeHigh; public uint FileSizeLow; public uint NumberOfLinks; public uint FileIndexHigh; public uint FileIndexLow; } } public class Test { public ulong ApproachA() { WinAPI.IO_STATUS_BLOCK iostatus=new WinAPI.IO_STATUS_BLOCK(); WinAPI._FILE_INTERNAL_INFORMATION objectIDInfo = new WinAPI._FILE_INTERNAL_INFORMATION(); int structSize = Marshal.SizeOf(objectIDInfo); FileInfo fi=new FileInfo(@"C:\Temp\testfile.txt"); FileStream fs=fi.Open(FileMode.Open,FileAccess.Read,FileShare.ReadWrite); IntPtr res=WinAPI.NtQueryInformationFile(fs.Handle, ref iostatus, memPtr, (uint)structSize, WinAPI.FILE_INFORMATION_CLASS.FileInternalInformation); objectIDInfo = (WinAPI._FILE_INTERNAL_INFORMATION)Marshal.PtrToStructure(memPtr, typeof(WinAPI._FILE_INTERNAL_INFORMATION)); fs.Close(); Marshal.FreeHGlobal(memPtr); return objectIDInfo.IndexNumber; } public ulong ApproachB() { WinAPI.BY_HANDLE_FILE_INFORMATION objectFileInfo=new WinAPI.BY_HANDLE_FILE_INFORMATION(); FileInfo fi=new FileInfo(@"C:\Temp\testfile.txt"); FileStream fs=fi.Open(FileMode.Open,FileAccess.Read,FileShare.ReadWrite); WinAPI.GetFileInformationByHandle(fs.Handle, out objectFileInfo); fs.Close(); ulong fileIndex = ((ulong)objectFileInfo.FileIndexHigh << 32) + (ulong)objectFileInfo.FileIndexLow; return fileIndex; } }
请看看这里: Windows的唯一文件ID 。 这也是有用的: 在NTFS文件的唯一ID?
用户还提到了唯一的目录标识。 这个过程比检索文件的唯一信息要复杂得多。 但是,这是可能的。 它要求你调用适当的CREATE_FILE
函数哪一个特定的标志。 用这个句柄,你可以在Ash的答案中调用GetFileInformationByHandle
函数。
这也需要一个kernel32.dll
导入:
[DllImport("kernel32.dll", SetLastError = true)] public static extern SafeFileHandle CreateFile( string lpFileName, [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile );
稍后我会详细讨论这个问题。 但是,用上面的相关答案,这应该开始有意义。 我最喜欢的一个资源是pinvoke ,它帮助了我.Net C#签名的可能性。