下面是一段代码,可以返回一个唯一的文件索引。
经过一番研究,我想出了ApproachA()。感谢Mattias和Rubens提供的链接,让我得到了ApproachB()。在我的基本测试中,两种方法都返回相同的文件索引。
以下是来自MSDN的一些注意事项:
文件ID的支持是特定于文件系统的。文件ID不能保证随时间保持唯一,因为文件系统可以重新使用它们。 在某些情况下,文件的文件ID可能会随时间变化。
在FAT文件系统中,文件ID是从包含目录的第一个簇和该文件条目所在目录中的字节偏移量生成的。一些碎片整理产品会更改此字节偏移量(Windows内置除碎片整理不会这样做)。因此,FAT文件ID可能会随时间变化。重命名FAT文件系统中的文件也可能会更改文件ID,但仅当新文件名比旧文件名长时才会发生。
在NTFS文件系统中,文件保持相同的文件ID,直到被删除。您可以使用ReplaceFile函数将一个文件替换为另一个文件,而不更改文件ID。但是,替换后的文件的文件ID,而不是被替换的文件,将保留为结果文件的文件ID。
以上第一个加粗的评论让我感到担忧。它并不清楚这个声明是否仅适用于FAT,它似乎与第二个加粗的文本相矛盾。我想进一步测试是唯一确定的方法。
[更新:在我的测试中,当文件从一个NTFS硬盘驱动器移动到另一个NTFS硬盘驱动器时,文件索引/ID会发生变化。]
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;
}
}
FileSystemWatcher
。 - CAD bloke