it-swarm.com.de

Eindeutige Dateikennung in Windows

Gibt es eine Möglichkeit, eine Datei (und möglicherweise Verzeichnisse) für die Lebensdauer der Datei unabhängig von Verschiebungen, Umbenennungen und Inhaltsänderungen eindeutig zu identifizieren? (Windows 2000 und höher). Durch das Erstellen einer Kopie einer Datei sollte der Kopie eine eindeutige Kennung zugewiesen werden.

Meine Anwendung verbindet verschiedene Metadaten mit einzelnen Dateien. Wenn Dateien geändert, umbenannt oder verschoben werden, ist es nützlich, Dateizuordnungen automatisch zu erkennen und zu aktualisieren.

FileSystemWatcher kann Ereignisse bereitstellen, die über diese Art von Änderungen informieren. Es verwendet jedoch einen Speicherpuffer, der leicht gefüllt werden kann (und Ereignisse verloren gehen), wenn viele Dateisystemereignisse schnell auftreten.

Ein Hash ist nicht sinnvoll, da sich der Inhalt der Datei ändern kann und sich der Hash somit ändert.

Ich hatte an das Dateierstellungsdatum gedacht, es gibt jedoch einige Situationen, in denen dies nicht eindeutig ist (dh wenn mehrere Dateien kopiert werden).

Ich habe auch von einer Datei-SID (Sicherheits-ID?) In NTFS gehört, aber ich bin mir nicht sicher, ob dies das tun würde, wonach ich suche.

Irgendwelche Ideen?

41
Ash

Wenn Sie GetFileInformationByHandle aufrufen, wird eine Datei-ID in BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low angezeigt. Dieser Index ist innerhalb eines Volumes eindeutig und bleibt gleich, auch wenn Sie die Datei (innerhalb des Volumes) verschieben oder umbenennen.

Wenn Sie davon ausgehen können, dass NTFS verwendet wird, möchten Sie möglicherweise auch alternative Datenströme zum Speichern der Metadaten in Betracht ziehen.

19
Mattias S

Beispielcode, der einen eindeutigen Dateiindex zurückgibt. 

AnsatzA () ist das, was ich nach ein bisschen Recherche gefunden habe. ApproachB () basiert auf Informationen in den Links von Mattias und Rubens. Bei einer bestimmten Datei geben beide Ansätze (während meines Grundtests) den gleichen Dateiindex zurück.

Einige Vorbehalte von MSDN:

Die Unterstützung für Datei-IDs ist systemspezifisch für Datei . Datei-IDs sind nicht Garantiert über die Zeit eindeutig, , Da Dateisysteme Frei wiederverwenden können. In einigen Fällen kann sich die Datei-ID für eine -Datei mit der Zeit ändern.

Im FAT-Dateisystem ist die Datei-ID , Die aus dem ersten Cluster von Des übergeordneten Verzeichnisses und dem Byte Offset innerhalb des Verzeichnisses des -Eintrags für die Datei. Einige Defragmentierungsprodukte ändern diesen Byte-Offset. (Die Defragmentierung im Windows-Postfach Funktioniert nicht.) Daher kann sich eine FAT -Datei-ID mit der Zeit ändern. Durch das Umbenennen von Einer Datei im FAT-Dateisystem kann Auch die Datei-ID geändert werden, jedoch nur, wenn der neue Dateiname Länger ist als der alte .

Im NTFS-Dateisystem behält eine Datei Die gleiche Datei-ID, bis sie gelöscht wird. . Sie können eine Datei durch eine andere -Datei ersetzen, ohne die Datei-ID zu ändern von mit der ReplaceFile-Funktion. Die Datei-ID der - Ersatzdatei, nicht die ersetzte -Datei, wird jedoch als Datei-ID von die resultierende Datei.

Der erste fette Kommentar oben macht mir Sorgen. Es ist nicht klar, ob diese Aussage nur für FAT gilt, sie scheint dem zweiten fetten Text zu widersprechen. Ich denke, weitere Tests sind der einzige Weg, um sicher zu gehen. 

[Update: Beim Testen ändert sich der Dateiindex/die ID, wenn eine Datei von einer internen NTFS-Festplatte auf eine andere interne NTFS-Festplatte verschoben wird.]

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

Bitte werfen Sie einen Blick hier: Eindeutige Datei-IDs für Windows . Dies ist auch nützlich: Eindeutige ID für Dateien unter NTFS?

4
Rubens Farias

Der Benutzer erwähnt auch die eindeutige Verzeichnisidentifikation. Dieser Vorgang ist etwas komplizierter als das Abrufen eindeutiger Informationen für eine Datei. es ist jedoch möglich. Es ist erforderlich, dass Sie den entsprechenden CREATE_FILEFunktion mit einem bestimmten Flag aufrufen. Mit diesem Handle können Sie die Funktion GetFileInformationByHandle in Ashs answer aufrufen.

Dies erfordert auch einen kernel32.dll-Import:

        [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
        );

Ich werde diese Antwort später noch ein bisschen ausarbeiten. Mit der oben verlinkten Antwort sollte dies jedoch sinnvoll erscheinen. Eine neue Lieblingsressource von mir ist pinvoke , die mir mit den .Net C # -Signaturmöglichkeiten geholfen hat. 

0
Thomas