Identifiant de fichier unique dans Windows

Existe-t-il un moyen d’identifier de manière unique un fichier (et éventuellement des répertoires) pendant toute la durée de vie du fichier, quels que soient les déplacements, les noms et les modifications de contenu? (Windows 2000 et versions ultérieures). Faire une copie d’un fichier devrait donner à la copie son propre identifiant unique.

Mon application associe différentes métadonnées à des fichiers individuels. Si des fichiers sont modifiés, renommés ou déplacés, il serait utile de pouvoir détecter et mettre à jour automatiquement les associations de fichiers.

FileSystemWatcher peut fournir des événements qui renseignent sur ces types de modifications, mais il utilise un tampon de mémoire pouvant être facilement rempli (et les événements perdus) si de nombreux événements de système de fichiers se produisent rapidement.

Un hachage ne sert à rien car le contenu du fichier peut changer et le hachage change.

J’avais pensé utiliser la date de création du fichier, mais il y a quelques situations où cela ne sera pas unique (par exemple, lorsque plusieurs fichiers sont copiés).

J’ai aussi entendu parler d’un fichier SID (ID de sécurité?) Dans NTFS, mais je ne suis pas sûr que cela fasse ce que je recherche.

Des idées?

Si vous appelez GetFileInformationByHandle , vous obtiendrez un ID de fichier dans BY_HANDLE_FILE_INFORMATION.nFileIndexHigh / Low. Cet index est unique dans un volume et rest identique même si vous déplacez le fichier (dans le volume) ou le renommez.

Si vous pouvez supposer que NTFS est utilisé, vous pouvez également envisager d’utiliser des stream de données alternatifs pour stocker les métadonnées.

Voici l’exemple de code qui renvoie un index de fichier unique.

ApproachA () est ce que j’ai trouvé après quelques recherches. ApproachB () est grâce aux informations contenues dans les liens fournis par Mattias et Rubens. Étant donné un fichier spécifique, les deux approches renvoient le même index de fichier (lors de mes tests de base).

Quelques mises en garde de MSDN:

La prise en charge des ID de fichier est spécifique au système de fichiers. Les identifiants de fichiers ne sont pas forcément uniques au fil du temps, car les systèmes de fichiers sont libres de les réutiliser. Dans certains cas, l’ID de fichier d’un fichier peut changer avec le temps.

Dans le système de fichiers FAT, l’ID du fichier est généré à partir du premier cluster du répertoire contenant et du décalage d’octet dans le répertoire de l’entrée du fichier. Certains produits de défragmentation modifient ce décalage d’octet. (La défragmentation Windows intégrée ne le permet pas). Par conséquent, un ID de fichier FAT peut changer avec le temps. Renommer un fichier dans le système de fichiers FAT peut également modifier l’ID du fichier, mais uniquement si le nouveau nom de fichier est plus long que l’ancien.

Dans le système de fichiers NTFS, un fichier conserve le même ID de fichier jusqu’à ce qu’il soit supprimé . Vous pouvez remplacer un fichier par un autre fichier sans modifier l’ID du fichier à l’aide de la fonction ReplaceFile. Toutefois, l’ID de fichier du fichier de remplacement, et non le fichier remplacé, est conservé comme ID du fichier résultant.

Le premier commentaire en gras me préoccupe. Il n’est pas clair si cette déclaration s’applique uniquement à la FAT, elle semble contredire le deuxième texte en caractères gras. Je suppose que des tests supplémentaires sont le seul moyen d’être sûr.

[Mise à jour: dans mes tests, l’index / ID du fichier change lorsqu’un fichier est déplacé d’un disque dur NTFS interne vers un autre disque dur NTFS interne.]

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 FileAtsortingbutes; 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; } } 

S’il vous plaît jeter un oeil ici: ID de fichiers uniques pour Windows . Ceci est également utile: ID unique pour les fichiers sur NTFS?

L’utilisateur mentionne également l’identification unique du répertoire. Ce processus est un peu plus compliqué que la récupération d’informations uniques pour un fichier; cependant, c’est possible. Cela vous oblige à appeler la fonction CREATE_FILE appropriée à un drapeau particulier. Avec cette poignée, vous pouvez appeler la fonction GetFileInformationByHandle dans la réponse de Ash.

Cela nécessite également une importation kernel32.dll :

  [DllImport("kernel32.dll", SetLastError = true)] public static extern SafeFileHandle CreateFile( ssortingng lpFileName, [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, IntPtr securityAtsortingbutes, [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, uint dwFlagsAndAtsortingbutes, IntPtr hTemplateFile ); 

Je vais développer cette réponse un peu plus tard. Mais, avec la réponse ci-dessus, cela devrait commencer à avoir un sens. Une de mes nouvelles ressources préférées est pinvoke, qui m’a aidé avec les possibilités de signature .Net C #.