This question already has answers here:
Closed 7 years ago.
Possible Duplicate:
Unique file identifier in windows
I need to retrieve a unique identifier for certain files on the computer, and have only came across the Win32 GetFileInformationByHandle function. How can I accomplish this with the. NET framework?
Update: I need a persistent id that will not change if the file is moved, updated, renamed, etc.
Update2: How can the same be accomplished with folders?
Here's some code from Ashley Henderson I copied from this answer. It implies two approaches which both return the same unique identifier.
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;
}
}
I assume the file format isn't under your control (otherwise, generatea UUID and store it there).
File Object ID's
NTFS supports object ID's on the file level, see FSCTL_CREATE_OR_GET_OBJECT_ID. I haven't used them to be able to recommend them, but it seems like a promising thing to explore.
As with alternate data streams (below), they can get lost when copying to a non-NTFS-medium ("usual" memory sticks, CD's, DVD's, flash cards, possibly even some USB disks. ...). Also, some applications might mess up when they recreate the file when saving.
Distributed Link Tracking Service
Distributed Link Tracking Service uses file object ID's for, well, tracking links to files, and repairing them when the file is moved.
AFAIK Distributed Link Tracking Service requires a domain controller for the server. Again, I have no practical experience with this.
On NTFS, you could also create and store a UUID in an alternate data stream.
Caveats:
- Only available on NTFS, will not "survive" on other file systems
- One white paper "the future of NTFS" considered killing them, but I fancy the thought there were some other features that could help you (unfortunately, I failed to dig that out)
- I wouldn't want to create that for thousands of files of unknown origin and purpose. Though they "just work" on the file system level, some applications might mess up.
Some document formats - such as Office - allow custom document properties.
That's obviously limited, but similar mechanisms can be piggybacked onto other file types as well. (e.g. many image formats would allow adding / rewriting "custom" chunks that should be ignored by readers)
FileFromID vs. IDFromFile
Alll solutions except DLTS only allow IDFromFile
lookup, i.e. locating a file that has moved (or was deleted) requires searching all potential drives.
For DLTS, if there's no "direct API" way, you could store a DLTS-enabled shortcut in an application-specific folder, and ~~hope for~~ expect the service to repair the shortcut when the file is moved.
You can get the MD5 hash for the files, take this example:
string GetMD5HashFromFile(string fileName)
{
FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
this will return a unique identifier for each file.