well, i decided to try a version that saves individual fields of each struct, written as binary. this way, when i add a new variable to a struct, i add it to save, then load and save the playtest games to convert them, then add it to load, and i'm done. i used inline wrappers for _fwrite_nolock. save times increased from 2 seconds for writing array of structs to 3 seconds for writing individual fields of structs. no keys. IDs, sizes, or version numbers, just the struct fields as they appear in the declarations. then i decided to try buffering it. i wrote a version that malloc'd a 100 meg buffer, memcpy'd the struct fields to the buffer, then wrote the entire thing with a single _fwrite_nolock. and then free the buffer of course. and buffering got me exactly sqaut. still 3 seconds to save.
lessons learned:
1. keeping the file open means you lose it if the power goes out. not a robust design.
2. buffering 60 meg of data vs writing it out one int and float and char[100] at a time did not provide any significant speedup. lots of calls to _fwrite_nolock is not a bottleneck.
3. writing more data slows things down (obviously). so the flexibility of a size,id,value format must be weighed against the overhead of the additional data written. a size,id,value format will always be slower than a format that simply saves fields in a pre-defined order.
4. its more work to save individual fields than it is to save an entire struct, so its more work at first to create the code to save a struct one field at a time. however its much less work to add a new variable to a struct and convert existing save files when saving things one field at a time.
In my case, i only have to deal with in-house old file formats. for dealing with old file formats on the user's pc, you'd init all your data structures to default values, then load. if you get EOF, stop loading. new variables always appear at the end of the file, so when you run out of file, that's all there is to load form this older format, and the newer vars use the default values. when it saves it uses the new format, saving the new vars along with the loaded old data. this lets you import older file formats by simply adding EOF checks to reads for new variables added to the end of the format.
has anyone heard of a "init, load vars til eof, save all" algo for automatically importing old save games? I don't recall that one in school (software engineering OSU). Algos from the regular world of computing (size,ID,value and "keep the file open") were mentioned. but as usual, what they teach in the regular computing world has issues (extra overhead or data loss on power outage) when it comes to using it for games.