Voici un exemple de code qui renvoie un index de fichier unique.
ApproachA() est la solution que j'ai trouvée après quelques recherches. ApprocheB() est grâce aux informations dans les liens fournis par Mattias et Rubens. Pour un fichier spécifique, les deux approches retournent le même index de fichier (pendant mes tests de base).
Quelques mises en garde de MSDN :
La prise en charge des ID de fichiers est le fichier est spécifique au système de fichiers. Les ID de fichiers ne sont pas garantis d'être uniques dans le temps, car les systèmes de fichiers sont libres de les réutiliser réutiliser. Dans certains cas, l'ID de fichier d'un fichier peut changer au fil du temps.
Dans le système de fichiers FAT, l'ID du fichier est le suivant généré à partir du premier cluster du du répertoire qui le contient et du décalage dans le répertoire de l'entrée pour le fichier. Certains produits de défragmentation produits de défragmentation modifient ce décalage des octets. (La défragmentation en boîte de Windows ne le fait pas). Ainsi, une FAT peut changer au fil du temps. Renommer un fichier dans le système de fichiers FAT peut également changer l'ID du fichier, mais uniquement si le nouveau nom de fichier est plus long que l'ancien nom de fichier.
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 changer l'ID du fichier en en utilisant la fonction ReplaceFile. Cependant, l'ID du fichier de fichier de remplacement, et non du fichier remplacé, est conservé comme identifiant du fichier fichier résultant.
Le premier commentaire en gras ci-dessus m'inquiète. Il n'est pas clair si cette déclaration s'applique uniquement à la FAT, elle semble contredire le deuxième texte en gras. Je suppose que des tests supplémentaires sont la seule façon d'en être sûr.
[Mise à jour : dans mes tests, l'index/identifiant du fichier change lorsqu'un fichier est déplacé d'un disque dur interne NTFS à un autre disque dur interne 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;
}
}