When writing software, you will often want to support multiple versions of a file format. Here is a quick guide that highlights some key concepts…
Generic File Header
- Define a file header (meta information at the beginning of the file) format that does not change, such that you can always read the file’s type and version, for any version of the file. For example:
- If your file is an INI file, create a section that looks like the following:[Header]
File Type = “MyFormat”
File Version = “1.0″
- If your file is binary, use fixed width strings for file type and version at the very beginning of the file.
- If your file is a CSV file, then make the first two rows store file type and version, such as the following:File Type, MyFormat
- Create a VI that can read the header (file type and version) from any version of your file — call it “MyFileType_ReadHeader.vi” (or similar).
Data Structure Type Definition
- Create a Type Definition of your Data Structure – You should have a type definition of the data structure that you are saving to file. Your reader/writer should output/input this type definition.
- Create a Snapshot of your Type Definition for Each Official Version – For each official version that your reader/writer will support, create a copy of the data structure and disconnect it (recursively) from any type definitions — this will be a “snapshot” of your type definition at the moment in time that you declared it to be a specific version. I’ll repeat myself: the snapshots should not be connected to any type definitions, since a snapshot should never be changed, once it is declared to be an official version.Note: The tricky part with this step is disconnecting a control from all type definitions, recursively. But, there are tools that can easily be made to automate this (download this example).
File Reader and Writer VIs
- Your file reader and writer VIs should output the type definition – However, inside your reader/writer you should coerce the type definition to the snapshot of the latest version. Now, if you modify your type definition, your reader/writer VI will be broken. This is an indication, at edit time, that you need to create a new version (and another snapshot) of your file version.
- Create a file reader and writer subVI for each version – You will need one subVI for each file version that handles converting the file into the data structure snapshot for that file version.Note: If you aren’t going to support a “save for previous” feature, you don’t need to be able to write every version.
- Create a version upgrade subVI and a version downgrade subVI for each file version – For all versions, except the first version, you will need a VI that handles converting data between neighboring versions. Additionally, you will need to implement some sort of upgrade path (maybe as a state machine) that handles calling the upgrade VIs to successively convert the data from older versions to the latest version.Note: If you aren’t going to support a “save for previous” feature, you don’t need to be able to downgrade to every version.
[UPDATE 2007-04-17] Example Download: “Disconnect Control from Typedef Recursive.vi“