Custom File Properties
I need to following:
In my application I have documents. Documents which need to be checked in and out all the time. When I check a Document out of my application I need to add Custom Properties to the file so I can identify it later when I'm going to checkin the document.
I've tried to use the OleDocumentProperties from DSOFile using the following code, but no success:
// Adding custom properties to file (Parameters: FileName, custom property name, value, debug: true/false
DocumentProperties.WriteDocumentProperty(filename, "dms_dossiernummer", _dossiernummer.ToString(), false);
DocumentProperties.WriteDocumentProperty(filename, "dms_zaaknaam", ReturnZaaknaam(_dossiernummer), false);
DocumentProperties.WriteDocumentProperty(filename, "dms_verantw_medew", ReturnVerantwMedew(_dossiernummer), false);
DocumentProperties.WriteDocumentProperty(filename, "dms_document_path", path, false);
DocumentProperties.WriteDocumentProperty(filename, "dms_bestandsnaam", bestandsNaam, false);
DocumentProperties.WriteDocumentProperty(filename, "dms_bestands_id", bestandId, false);
DocumentProperties.WriteDocumentProperty(filename, "dms_is_checkedout", "true", false);
DocumentProperties.WriteDocumentProperty(filename, "dms_dossier_map_id", dossierMapId, false);
DocumentProperties.WriteDocumentProperty(filename, "dms_bestand_versie_nummer", Queries.Dms.Selects.GetDocumentVersion(
Convert.ToInt32(bestandId)).ToString(), false);
DocumentProperties.WriteDocumentProperty(filename, "dms_bestands_locatie", path, false);
Does anyone know another way to add Custom File Properties to a file?
Solution 1:
What is a File?
Basically, a file is just a stream of bytes and some metadata that file file system associates with it. In early file systems the metadata was basically just the file name and some date stamps. Newer file systems like NTFS have the option of adding extra metadata.
Where do Document Properties Come From?
In Windows Explorer you can see quite a lot of document properties for many file types. The nice, unified interface suggests that there is some unified property store. That's not really the case. The Explorer Shell has an extensible interface for Property Sheet Handlers that extract this information from various file types. There is a handler for JFIF (JPEG) files, and there are handlers for OLE files (old Office formats), and the new Office formats too.
Where Should I Put My Metadata?
The conclusion is:
-
If you can guarantee that you only need to handle certain file formats, investigate adding the metadata within the files. For example,
OLE properties if all your files are old-style Office documents (.doc)
Using the Open XML API if all your documents are new-style Office documents (.docx)
If you can guarantee that all installations will be on a specific file system, investigate features of the file system. Other responses have considered how you could do this with NTFS.
Otherwise you must devise your own data store. Companion files are an obvious possibility; you could store the metadata in a database; or you could create one file per directory to hold all the metadata for files in that directory. Consider whether you might face concurrency problems with multiple requests for the same file. Using a database might make dealing with that more straightforward.
Solution 2:
An alternate data stream will allow you to store any data that you want. Beware; if you copy the file to a non NTFS file system, the extra data will get stripped out.
Here is an article that should get you started
-- Edit 1/2/2014 --
Here are some more:
http://www.codeproject.com/Articles/2670/Accessing-alternative-data-streams-of-files-on-an
http://www.dreamincode.net/forums/topic/90666-reading-and-writing-alternate-streams-in-c%23/
NTFS Alternate Data Streams - .NET
And one for creating/viewing ADS from the command line: http://www.undermyhat.org/blog/2012/05/copy-delete-or-rename-alternate-data-streams-using-only-standard-windows-command-prompt-tools/
Solution 3:
Though any kind of file can be opened using DSOFile.dll, custom properties will not be persisted, except for files that are OLE Structured Storages / Ole Documents (http://en.wikipedia.org/wiki/COM_Structured_Storage) like older formats of Microsoft Office files (.doc, .xls, etc) and some CAD files.
As Brad wrote, you can go with alternate data streams, but that has a dependency too, the NTFS file system.
I don't recommend you to go these ways...
What if you used a new file ie. <original file>.props
or such?
Solution 4:
There are multiple options here.
As mentioned above, alternate data streams are a good option if you can guarantee your file will always be located on NTFS.
You can just write your custom properties as JSON, XML, serialized objects, or even a simple line + delimiter format.
Unfortunately these aren't fully available using .NET, you have to use P/Invoke and CreateFile.
[DllImport( "kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true )]
private static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
You'll then have to create the data stream with the file path, followed by a colon, followed by the name of the stream as the filename and pass the SafeFileHandle returned by CreateFile to the constructor of FileStream. All the other options of CreateFile are as normal for opening a file via this API.
Note that if you want to write to an alternate data stream, you must have write access to the file.
Here's the reference for CreateFile. http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
Here's some useful constants:
private const uint GENERIC_WRITE = 0x40000000;
private const uint GENERIC_READ = 0x80000000;
private const uint FILE_SHARE_READ = 0x00000001;
private const uint FILE_SHARE_WRITE = 0x00000002;
private const uint CREATE_NEW = 1;
private const uint CREATE_ALWAYS = 2;
private const uint OPEN_EXISTING = 3;
private const uint OPEN_ALWAYS = 4;
A method that doesn't require P/Invoke and is friendly to file systems other than NTFS is to create a second file with the full pathname of the original file + another extension added. Again, you can use your preferred method of storing the properties in this file. However, this has the disadvantage that if your user moves the files, they have to move the properties too.