Уникальный идентификатор файла в Windows
есть ли способ однозначно идентифицировать файл (и, возможно, каталоги) для времени жизни файла независимо от перемещений, переименований и изменений содержимого? (Windows 2000 и позже). Создание копии файла должно дать копии собственный уникальный идентификатор.
мое приложение связывает различные метаданные с отдельными файлами. Если файлы изменены, переименованы или перемещены, было бы полезно иметь возможность автоматически обнаруживать и обновлять файл объединения предпринимателей.
FileSystemWatcher может предоставить события, которые сообщают о таких изменениях, однако он использует буфер памяти, который может быть легко заполнен (и события потеряны), если многие события файловой системы происходят быстро.
хэш бесполезен, потому что содержимое файла может измениться, и поэтому хэш изменится.
Я думал об использовании даты создания файла, однако есть несколько ситуаций, когда это не будет уникальным (т. е. когда несколько файлов скопированный.)
Я также слышал о файле SID (Security ID?) в NTFS, но я не уверен, что это сделает то, что я ищу.
какие идеи?
4 ответов
Если вы называете GetFileInformationByHandle, вы получите идентификатор файла в BY_HANDLE_FILE_INFORMATION.nFileIndexHigh / Low. Этот индекс уникален в пределах Тома и остается неизменным, даже если вы перемещаете файл (в пределах тома) или переименовываете его.
Если вы можете предположить, что используется NTFS, вы также можете рассмотреть возможность использования альтернативных потоков данных для хранения метаданных.
вот пример кода, который возвращает уникальный индекс файла.
подхода () - это то, что я придумал после немного исследований. ApproachB () - это благодаря информации в ссылках, предоставленной Маттиасом и Рубенсом. Учитывая конкретный файл, оба подхода возвращают один и тот же индекс файла (во время моего базового тестирования).
некоторые предостережения от MSDN:
поддержка идентификаторов файлов-это файл конкретной системы. Идентификаторы файлов не гарантированно быть уникальным с течением времени, потому что файловые системы можно использовать повторно их. в некоторых случаях, идентификатор файла на файл может меняться со временем.
в файловой системе FAT идентификатор файла генерируется из первого кластера содержащий каталог и Байт смещение в каталог запись для файла. Некоторые продукты дефрагментации изменяют это смещение байта. (Окна в окна дефрагментация не.) Таким образом, жир идентификатор файла может меняться со временем. Переименование файл в файле FAT система может также измените идентификатор файла, но только если новое имя файла длиннее старого один.
в файловой системе NTFS файл сохраняется тот же идентификатор файла, пока он не будет удален. Вы можете заменить один файл другим файл без изменения идентификатора файла использование функции ReplaceFile. Однако, идентификатор файла файл замены, а не замененный файл, сохраняется как идентификатор файла результирующий файл.
первый смелый комментарий выше беспокоит меня. Неясно, относится ли это утверждение только к FAT, оно, похоже, противоречит второму выделенному жирным шрифтом тексту. Думаю, дальнейшее тестирование-единственный способ убедиться.
[Update: в моем тестировании индекс/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?
пользователь также упоминает уникальную идентификацию каталога. Этот процесс немного более запутан, чем получение уникальной информации для файла; однако это возможно. Он требует, чтобы вы позвонили в соответствующий CREATE_FILE
функции какой конкретный флаг. С этой ручкой вы можете вызвать 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#.