Obtenir un ID de dossier C #

J’essaie de suivre des fichiers et des dossiers tout au long de leur vie (ils peuvent être déplacés ou renommés). J’ai effectué une recherche et trouvé que FileSystemWatcher pourrait être le moyen le plus populaire de suivre les fichiers et les dossiers, mais cela ne fonctionnera pas pour moi, car l’application peut ou non être toujours en cours d’exécution. J’ai choisi d’essayer de suivre les dossiers via un identifiant.

J’ai trouvé un moyen de suivre les fichiers à partir d’un ID à partir de la réponse à cette publication . Je peux récupérer avec succès des identifiants de fichiers basés sur l’approche B dans cette réponse .

Lors de la recherche, j’ai trouvé cet article de la stack indiquant qu’il avait trouvé sa solution en utilisant FSCTL_GET_OBJECT_ID . J’ai passé pas mal de temps à essayer de comprendre comment utiliser cette fonction, mais je ne peux pas la comprendre. Je n’ai pratiquement aucune expérience en appelant des fonctions Windows natives depuis C #.

Quelqu’un peut-il me donner un coup de pouce dans la bonne direction pour cela? J’ai l’impression que je dois rater quelque chose d’évident.

Y a-t-il une raison pour laquelle C # ne peut pas accéder aux ID de fichier / dossier? Le suivi des fichiers / dossiers est-il rare?

Modifier, append du code:

static uint returnVal; //Working example to get File ID public static ssortingng GetFileId(ssortingng path) { WinAPI.BY_HANDLE_FILE_INFORMATION objectFileInfo = new WinAPI.BY_HANDLE_FILE_INFORMATION(); FileInfo fi = new FileInfo(path); 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.ToString(); } public static string GetFolderId(string path) { //Get a handle on the given folder IntPtr cFile = WinAPI.CreateFile( path, WinAPI.GENERIC_READ, FileShare.Read, IntPtr.Zero, (FileMode)WinAPI.OPEN_EXISTING, WinAPI.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); Console.WriteLine(path); Console.WriteLine(cFile); if ((int)cFile != -1) { int cFileSize = Marshal.SizeOf(typeof(IntPtr)); Console.WriteLine("cFile size = {0}", cFileSize); IntPtr cFileBlob = Marshal.AllocHGlobal(cFileSize); uint numBytesRead = 0; WinAPI.DeviceIoControl(cFile, WinAPI.FSCTL_GET_OBJECT_ID, IntPtr.Zero, 0, cFileBlob, (uint)cFileSize, ref numBytesRead, IntPtr.Zero); if (returnVal == 0) { Console.WriteLine(Marshal.GetLastWin32Error()); // Returning error 87 here } } //Should be returning the ID from the folder. return String.Empty; } public static void Main(string[] args) { Console.WriteLine(GetFileId(@"C:\Users\Matt\Desktop\TestDocument.txt")); Console.WriteLine(GetFolderId(@"C:\Users\Matt\Desktop")); } } class WinAPI { // Win32 constants for accessing files. internal const int GENERIC_READ = unchecked((int)0x80000000); internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000); internal const int OPEN_EXISTING = unchecked((int)3); internal const int FSCTL_GET_OBJECT_ID = 0x0009009c; internal const int FSCTL_CREATE_OR_GET_OBJECT_ID = 0x000900c0; [DllImport("kernel32.dll", SetLastError = true)] public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, [Out] IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateFile( String fileName, int dwDesiredAccess, System.IO.FileShare dwShareMode, IntPtr securityAttrs_MustBeZero, System.IO.FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile_MustBeZero); 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; } } 

Je reçois l’erreur “87” de DeviceIoControl, qui est un paramètre non valide selon une publication sur MSDN (je ne peux pas publier plus de liens en raison de ressortingctions de réputation).

Il semblerait que vous n’ayez aucun problème avec FileSystemWatcher . Donc, pour savoir comment utiliser DeviceIoControl dans C #, regardez cette réponse:

La taille du disque physique n’est pas correcte (IoCtlDiskGetDriveGeometry)

A cette question, il est fait avec le code suivant:

 class Program { const uint FSCTL_GET_OBJECT_ID=0x0009009c; public static Ssortingng GetFileId(Ssortingng path) { using(var fs=File.Open( path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite) ) { WinAPI.BY_HANDLE_FILE_INFORMATION info; WinAPI.GetFileInformationByHandle(fs.Handle, out info); return Ssortingng.Format( "{0:x}", ((info.FileIndexHigh<<32)|info.FileIndexLow)); } } public static WinAPI.FILE_OBJECTID_BUFFER GetFolderIdBuffer(String path) { using(var hFile=WinAPI.CreateFile( path, WinAPI.GENERIC_READ, FileShare.Read, IntPtr.Zero, (FileMode)WinAPI.OPEN_EXISTING, WinAPI.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero )) { if(null==hFile||hFile.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); var buffer=default(WinAPI.FILE_OBJECTID_BUFFER); var nOutBufferSize=Marshal.SizeOf(buffer); var lpOutBuffer=Marshal.AllocHGlobal(nOutBufferSize); var lpBytesReturned=default(uint); var result= WinAPI.DeviceIoControl( hFile, FSCTL_GET_OBJECT_ID, IntPtr.Zero, 0, lpOutBuffer, nOutBufferSize, ref lpBytesReturned, IntPtr.Zero ); if(!result) throw new Win32Exception(Marshal.GetLastWin32Error()); var type=typeof(WinAPI.FILE_OBJECTID_BUFFER); buffer=(WinAPI.FILE_OBJECTID_BUFFER) Marshal.PtrToStructure(lpOutBuffer, type); Marshal.FreeHGlobal(lpOutBuffer); return buffer; } } public static void Main(String[] args) { Console.WriteLine( GetFileId(@"C:\Users\Matt\Desktop\TestDocument.txt")); var buffer=GetFolderIdBuffer(@"C:\Users\Matt\Desktop"); var objectId=buffer.ObjectId .Reverse() .Select(x => x.ToSsortingng("x2")) .Aggregate(Ssortingng.Concat); Console.WriteLine("{0}", objectId); } } class WinAPI { internal const int GENERIC_READ=unchecked((int)0x80000000), FILE_FLAG_BACKUP_SEMANTICS=unchecked((int)0x02000000), OPEN_EXISTING=unchecked((int)3); [StructLayout(LayoutKind.Sequential)] public struct FILE_OBJECTID_BUFFER { public struct Union { [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] public byte[] BirthVolumeId; [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] public byte[] BirthObjectId; [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] public byte[] DomainId; } [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)] public byte[] ObjectId; public Union BirthInfo; [MarshalAs(UnmanagedType.ByValArray, SizeConst=48)] public byte[] ExtendedInfo; } [StructLayout(LayoutKind.Sequential)] 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; } [DllImport("kernel32.dll", SetLastError=true)] public static extern bool DeviceIoControl( SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, [Out] IntPtr lpOutBuffer, int nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped ); [DllImport("kernel32.dll", SetLastError=true)] public static extern SafeFileHandle CreateFile( Ssortingng fileName, int dwDesiredAccess, System.IO.FileShare dwShareMode, IntPtr securityAttrs_MustBeZero, System.IO.FileMode dwCreationDisposition, int dwFlagsAndAtsortingbutes, IntPtr hTemplateFile_MustBeZero ); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool GetFileInformationByHandle( IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation); } 

L’espace de nom est requirejs pour utiliser:

 using Microsoft.Win32.SafeHandles;