Unieke bestandsidentificatie in windows

Is er een manier om een ​​bestand (en mogelijk mappen) op unieke wijze te identificeren voor de levensduur van het bestand, ongeacht verplaatsingen, hernoemingen en inhoudswijzigingen? (Windows 2000 en hoger). Het maken van een kopie van een bestand zou de kopie zijn eigen unieke identificatiecode moeten geven.

Mijn applicatie koppelt verschillende metadata aan individuele bestanden. Als bestanden worden gewijzigd, hernoemd of verplaatst, zou het handig zijn om bestandsassociaties automatisch te kunnen detecteren en bijwerken.

FileSystemWatcher kan gebeurtenissen leveren die op de hoogte zijn van dit soort wijzigingen, maar het gebruikt een geheugenbuffer die gemakkelijk kan worden gevuld (en gebeurtenissen kunnen verloren gaan) als veel bestandssysteemgebeurtenissen snel plaatsvinden.

Een hash heeft geen zin omdat de inhoud van het bestand kan veranderen, en dus zal de hash veranderen.

Ik had gedacht om de aanmaakdatum van het bestand te gebruiken, maar er zijn een paar situaties waarin dit niet uniek is (bijv. wanneer meerdere bestanden worden gekopieerd).

Ik heb ook gehoord van een bestands-SID (beveiligings-ID?) in NTFS, maar ik weet niet zeker of dit zou doen wat ik zoek.

Enig idee?


Antwoord 1, autoriteit 100%

Hier is een voorbeeldcode die een unieke bestandsindex retourneert.

ApproachA() is wat ik bedacht na wat onderzoek. ApproachB() is te danken aan de informatie in de links van Mattias en Rubens. Gegeven een specifiek bestand, retourneren beide benaderingen dezelfde bestandsindex (tijdens mijn basistests).

Enkele waarschuwingen van MSDN:

Ondersteuning voor bestands-ID’s is bestand
systeemspecifiek. Bestands-ID’s zijn niet
gegarandeerd uniek in de tijd,
omdat bestandssystemen vrij kunnen worden hergebruikt
hen. In sommige gevallen is de bestands-ID voor a
bestand kan in de loop van de tijd veranderen.

In het FAT-bestandssysteem is de bestands-ID
gegenereerd uit de eerste cluster van
de bevattende map en de byte
offset binnen de directory van de
invoer voor het bestand. Sommige
defragmentatieproducten veranderen dit
byte-offset. (Windows in-box)
defragmentatie niet.) Dus een FAT
bestands-ID kan in de loop van de tijd veranderen. Hernoemen
een bestand in het FAT-bestandssysteem kan ook:
verander de bestands-ID, maar alleen als de
nieuwe bestandsnaam is langer dan de oude
een.

In het NTFS-bestandssysteem wordt een bestand bewaard
dezelfde bestands-ID totdat deze wordt verwijderd
.
U kunt het ene bestand door het andere vervangen
bestand zonder de bestands-ID te wijzigen door
met behulp van de functie ReplaceFile.
De bestands-ID van de
vervangend bestand, niet het vervangen
bestand, wordt behouden als de bestands-ID van
het resulterende bestand.

De eerste vetgedrukte opmerking hierboven baart me zorgen. Het is niet duidelijk of deze verklaring alleen van toepassing is op FAT, het lijkt in tegenspraak met de tweede vetgedrukte tekst. Ik denk dat verder testen de enige manier is om zeker te zijn.

[Update: tijdens mijn tests verandert de bestandsindex/-id wanneer een bestand wordt verplaatst van de ene interne NTFS-harde schijf naar een andere interne NTFS-harde schijf.]

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

2, Autoriteit 74%

Als u getfileinformationbyhandle , u ‘ Ik krijg een bestand-ID in by_handle_file_information.nfileindexhigh / low. Deze index is uniek binnen een volume en blijft hetzelfde, zelfs als u het bestand verplaatst (binnen het volume) of hernoem het.

Als u kunt aannemen dat NTFS wordt gebruikt, wilt u ook overwegen om alternatieve gegevensstromen te gebruiken om de metadata op te slaan.


3, Autoriteit 11%

Neem hier een kijkje: unieke bestands-ID’s voor Windows . Dit is ook handig: unieke ID voor bestanden op ntfs?


4, Autoriteit 3%

Eén ding dat u kunt gebruiken voor file-uids is het tijdstip Create, zorg ervoor dat u de bestanden in uw programma scant, die u createdimes betreft die hetzelfde zijn als die al is aangetroffen, zodat ze het minutieus anders zijn Op NTF’s kan anders dezelfde TS hebben als ze tegelijkertijd werden gemaakt door een kopie van de massabestand, maar in de normale loop van de dingen krijg je niet duplicaten en het aanpassen zal weinig zijn. d

Other episodes