当前位置:  开发笔记 > 编程语言 > 正文

Windows中的唯一文件标识符

如何解决《Windows中的唯一文件标识符》经验,为你挑选了2个好方法。

无论移动,重命名和内容修改,是否有办法在文件的生命周期内唯一标识文件(可能还有目录)?(Windows 2000及更高版本).制作文件的副本应该为副本提供它自己的唯一标识符.

我的应用程序将各种元数据与单个文件相关联.如果修改,重命名或移动文件,则能够自动检测和更新文件关联将非常有用.

FileSystemWatcher可以提供通知这些更改的事件,但是如果快速发生许多文件系统事件,它会使用可以轻松填充(和事件丢失)的内存缓冲区.

哈希是没有用的,因为文件的内容可以改变,因此哈希值会改变.

我曾想过使用文件创建日期,但是有一些情况下这不是唯一的(即复制多个文件时).

我还听说过NTFS中的文件SID(安全ID?),但我不确定这是否能满足我的要求.

有任何想法吗?



1> Ash..:

这是返回唯一文件索引的示例代码.

ApproachA()是经过一番研究后我想出来的.ApproachB()归功于Mattias和Rubens提供的链接中的信息.给定一个特定文件,两种方法都返回相同的文件索引(在我的基本测试期间).

来自MSDN的一些警告:

对文件ID的支持是特定于文件系统的.文件ID不保证随着时间的推移是唯一的,因为文件系统可以自由地重用它们.在某些情况下,文件的文件ID可能会随时间而变化.

在FAT文件系统中,文件ID是从包含目录的第一个簇和文件条目目录中的字节偏移量生成的.一些碎片整理产品会更改此字节偏移量.(Windows内置碎片整理不会.)因此,FAT文件ID可能会随时间而变化.重命名FAT文件系统中的文件也可以更改文件ID,但前提是新文件名长于旧文件名.

在NTFS文件系统中,文件保留相同的文件ID,直到删除为止.您可以使用ReplaceFile函数将一个文件替换为另一个文件,而无需更改文件ID.但是,替换文件的文件ID(而不是替换文件)将保留为生成的文件的文件ID.

上面的第一个粗体评论让我担心.目前尚不清楚这个陈述是否仅适用于FAT,它似乎与第二个粗体文本相矛盾.我想进一步测试是确定的唯一方法.

[更新:在我的测试中,当文件从一个内部NTFS硬盘驱动器移动到另一个内部NTFS硬盘驱动器时,文件索引/ ID会发生变化.

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


很好,我试了一下,但发现了一个问题:它不适用于像Microsoft Office套件(doc,docx,xl​​s ......)这样的文件,因为每次进行更改时,Office都会删除该文件,并创建一个新的文件替换它,这个结果参考号改变了,虽然参考号仍然是唯一的.它无法检测这些文件中的更改,也许其他一些程序也会采用类似的方法.所以我想我会回到我的CreationTime方法......

2> 小智..:

如果您调用GetFileInformationByHandle,您将获得BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low中的文件ID.该索引在卷中是唯一的,即使您移动文件(在卷内)或重命名它也保持不变.

如果您可以假设使用了NTFS,则可能还需要考虑使用备用数据流来存储元数据.


GetFileInformationByHandle的文档说:"nFileIndexLow:与文件关联的唯一标识符的低位部分.此值仅在文件被至少一个进程打开时才有用.如果没有进程打开,则索引可能下次打开文件时更改."
推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有