How to handle saving and loading different versions of a file? - algorithm
In making an application that saves files with a specific format which in the future will have added or different functionality, requiring the saved file to have a different format, are there any techniques available to handle this "versioning"?
I would be interested in reading into some of them explaining how it is possible to load all the possible formats of the saved file that were created by the different versions of the application.
My idea currently is to save a version indicator in the saved file and use distinct load functions for every "version" that had it's own format, trying to tie them all with the current functionality of the latest version of the app.
This is mostly opinion based so handle it as such... Here are my insights on the topic:
fileformat
You should have 2 identificators. One for file format sometimes called magic number and second version. Both should be somewhere at the start of file and usually encoded as ASCII so you can easily check them with notepad or whatever.
Its a good idea to have chunks of data with they own type and version identificators.
loader - single fileformat detector
I use this to check for specific fileformat. The input is array (small usually 1Kbyte) holding first bytes of file, array size and file size. The function checks if the file is valid file of some type. This is used to autodetect fileformat and not relay on file extension (necessity on Windows and low grade users as they often corrupt the file extention)
The function returns true/false after checking identificators (and or file logic)
loader - single fileformat
This should load file into your app. For multi versions you got 2 options. Either have separate code for each version or one function partitioned with if statements like this:
if (version==???) ...
if (version>=???) ... else ...
if ((version>=???)&&(version<???)) ...
to manage the diferent parts.
I prefer the partitioned code approach as its usually less code and better manageable because different versions usually adds just some minor changes and most of the code states the same.
loader - multi fileformat
Simply load first bytes of file into memory and check all the supported fileformats using function from #2. Once succesfully detected fileformat load the file using its loader function from #3. If no fileformat detected then use file extention ...
Here simple C++/VCL example of #4 from my SVG loader class:
bool decode_interface_class::load(AnsiString name)
{
int hnd=-1;
int siz=0,siz0=0;
BYTE *dat=NULL;
reset();
#ifdef decode_interface_log
decode_id.num=0;
decode_log="";
#endif
decode_cfg =true;
decode_col =true;
decode_tool=true;
decode_ext=ExtractFileExt(name).LowerCase();
decoded_ext=".";
decoded_info="";
decode_emf emf;
decode_wmf wmf;
decode_dkr dkr;
decode_dk3 dk3;
decode_box box;
decode_bxl bxl;
decode_dxf dxf;
decode_svg svg;
decode_v2x v2x;
decode_v2d v2d;
const int _size=4096;
BYTE head[_size];
#ifdef decode_interface_log
siz=0; // find minimal size
if (siz<_decode_emf_hdr) siz=_decode_emf_hdr;
if (siz<_decode_wmf_hdr) siz=_decode_wmf_hdr;
if (siz<_decode_dkr_hdr) siz=_decode_dkr_hdr;
if (siz<_decode_dk3_hdr) siz=_decode_dk3_hdr;
if (siz<_decode_box_hdr) siz=_decode_box_hdr;
if (siz<_decode_bxl_hdr) siz=_decode_bxl_hdr;
if (siz<_decode_dxf_hdr) siz=_decode_dxf_hdr;
if (siz<_decode_svg_hdr) siz=_decode_svg_hdr;
if (siz<_decode_v2x_hdr) siz=_decode_v2x_hdr;
if (siz<_decode_v2d_hdr) siz=_decode_v2d_hdr;
if (siz>_size)
{
decode_log+="Decoding header size too small needed to be "+AnsiString(siz)+" Bytes.\r\n";
}
#endif
hnd=FileOpen(name,fmOpenRead);
if (hnd<0)
{
#ifdef decode_interface_log
decode_log+="File "+name+" not found.\r\n";
#endif
return false;
}
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new BYTE[siz];
if (dat==NULL)
{
#ifdef decode_interface_log
decode_log+="Not enough memory need: "+AnsiString(siz)+" Bytes.\r\n";
#endif
FileClose(hnd);
return false;
}
siz0=siz;
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
if (siz!=siz0)
{
#ifdef decode_interface_log
decode_log+="Disc drive or file system error.\r\n";
#endif
}
this[0].filename=name;
// file signature detection
for (int i=0;i<_size;i++) if (i<siz) head[i]=dat[i]; else head[i]=0;
if (emf.is_header(head,_size,siz)) { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); }
else if (wmf.is_header(head,_size,siz)) { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); }
else if (dkr.is_header(head,_size,siz)) { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); }
else if (dk3.is_header(head,_size,siz)) { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); }
else if (box.is_header(head,_size,siz)) { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); }
else if (bxl.is_header(head,_size,siz)) { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); }
else if (dxf.is_header(head,_size,siz)) { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); }
else if (svg.is_header(head,_size,siz)) { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); }
else if (v2x.is_header(head,_size,siz)) { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); }
else if (v2d.is_header(head,_size,siz)) { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); }
// if fail use file extension
else if (decode_ext==_decode_emf_ext) { decoded_ext=_decode_emf_ext; emf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_wmf_ext) { decoded_ext=_decode_wmf_ext; wmf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dkr_ext) { decoded_ext=_decode_dkr_ext; dkr.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dk3_ext) { decoded_ext=_decode_dk3_ext; dk3.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_box_ext) { decoded_ext=_decode_box_ext; box.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_bxl_ext) { decoded_ext=_decode_bxl_ext; bxl.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_dxf_ext) { decoded_ext=_decode_dxf_ext; dxf.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_svg_ext) { decoded_ext=_decode_svg_ext; svg.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_v2x_ext) { decoded_ext=_decode_v2x_ext; v2x.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
else if (decode_ext==_decode_v2d_ext) { decoded_ext=_decode_v2d_ext; v2d.load(this[0],dat,siz); decoded_info="*"+decoded_info; }
// if fail then error
else{
#ifdef decode_interface_log
decode_log+="File "+name+" not recognized.\r\n";
#endif
}
if (decode_cfg)
{
if (!decode_col )
{
if (decode_tool) set_cfgs (dk3_charaktool ,33);
set_colors(dk3_charakcolor,33);
}
if (!decode_tool) set_tools (dk3_charaktool ,33);
}
#ifdef decode_interface_log
if (decode_ext!=decoded_ext)
decode_log+="Wrong file extension in "+name+" should be \""+decoded_ext+"\"\r\n";
hnd=FileCreate(ExtractFilePath(Application->ExeName)+"svg_decode.log");
FileWrite(hnd,decode_log.c_str(),decode_log.Length());
FileClose(hnd);
#endif
compute();
compute_objsize();
if (dat) delete[] dat;
return true;
}
Each fileformat has defined its header size _decode_???_hdr in bytes and default file extention _decode_??_ext for the detection of fileformat. Functions ???.is_header(...) are the #2 and ???.load(...) are the #3. I am using loading from memory instead of direct file access because its better suite my needs. However this is not convenient for too big files.
Related
UWP won't compile GetBufferFromString in Microsoft example for FileIO.WriteBufferAsync
I'm trying to use WriteBufferAsync in the Microsoft example for FileIO.WriteBufferAsync but GetBufferFromString doesn't compile. Ultimately, I want to write a byte buffer to an absolute file path. This is a copy from the example... try { if (file != null) { IBuffer buffer = GetBufferFromString("Swift as a shadow"); await FileIO.WriteBufferAsync(file, buffer); // Perform additional tasks after file is written } } // Handle errors with catch blocks catch (FileNotFoundException) { // For example, handle file not found }
GetBufferFromString doesn't compile. #Raymond Chen's comments are very convincing. And he is the author of the UWP official code sample. The reason why GetBufferFromString could not be compiled is you have not declared it. private IBuffer GetBufferFromString(String str) { using (InMemoryRandomAccessStream memoryStream = new InMemoryRandomAccessStream()) { using (DataWriter dataWriter = new DataWriter(memoryStream)) { dataWriter.WriteString(str); return dataWriter.DetachBuffer(); } } } I want to write a byte buffer to an absolute file path. For writing a buffer to an absolute file path, you could use PathIO.WriteBufferAsync method. Please note, you need make sure your file could be accessed within uwp. for example, if your file stored in picture library, you need add Picture capability. for more detail please refer UWP file access permissions.
libtorrent alerts - read_piece_alert
I have a multi-file torrent (3 files). I subscribed to read_piece_alert as explained here. std::vector<alert*> alerts; ses.pop_alerts(&alerts); for (alert* i : alerts) { switch (a->type()) { case read_piece_alert::alert_type: { read_piece_alert* p = (read_piece_alert*)a; if (p->ec) { // read_piece failed break; } // use p break; } case file_renamed_alert::alert_type: { // etc... } } } How can I know to which file the piece belongs in the multi-file torrent? For example my multi-file torrent has an .AVI, .TXT and .JPG. Is there some kind of index to know to which file the piece actually belongs?
yes. you can map a piece-index into one or more file-indices + offsets with the map_block() function on file_storage. See the documentation.
Efficiently write log file on Windows
I want to write log files. My application could be run on Linux and Windows. I've pretty much figured out how to do it for the former, thanks to this example: void SyslogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context) QByteArray localMsg = msg.toLocal8Bit(); switch (type) { case QtDebugMsg: #ifdef __linux__ syslog(LOG_DEBUG, "Message (debug): %s", localMsg.constData()); #elif _WIN32 // WRITE INTO FILE #else #endif break; // etc. } } int main() { // Install our message handler. qInstallMessageHandler(SyslogMessageHandler); // Send some messages, which should go to syslog. qDebug("Debug log message from Qt test program"); } source (2nd example) However, I am wondering what would be the fastest way for Windows? Is using QFile or QTextStream an efficient way for writing this kind of information? I was thinking about storing everything in a simple QString and then put everything in a file when the app closes or crashes (in the latter case, is that possible?).
How To Save Settings in Qt
I wrote some codes for an application and I want to save this Settings Like Hide a lineEdit or etc... and when reopen program last settings will load and when user edit setting settings that saved updates what I must do? note: I Used Qsettings but settings dose not saved! if Possible one person Write a Sample Code For me That save current index of a combobox QSettings settings("Mobtakeran Fanavri KabooK","Kabook Physiothrapy"); Secretary::Secretary(QWidget *parent) : QWidget(parent), ui(new Ui::Secretary) { ui->setupUi(this); ui->comboBox->setCurrentIndex(settings.value("comboBox").toInt()); } Secretary::~Secretary() { QCoreApplication::setOrganizationName("Mobtakeran Fanavri KabooK"); QCoreApplication::setOrganizationName("WWW.M4RZB4Ni.IR"); QCoreApplication::setApplicationName("Kabook Physiothrapy"); delete ui; } void Secretary::on_comboBox_currentIndexChanged(int index) { settings.beginGroup("comboBox"); if(ui->comboBox->currentIndex()==2) { ui->pushButton_3->setDisabled(true); } else if(ui->comboBox->currentIndex()==1) { ui->pushButton_3->hide(); settings.setValue("comboBox",ui->comboBox->currentIndex()); } else if(ui->comboBox->currentIndex()==0) { if(ui->lineEdit_56->text()==NULL) { ui->pushButton_8->setDisabled(true); } } settings.endGroup(); }
when you are saving your settings in Secretary::on_comboBox_currentIndexChanged you are calling settings.beginGroup("comboBox") then you set the value settings.setValue("comboBox",ui->comboBox->currentIndex()). According to the documentation, this will set the value of the settings "comboBox/comboBox", meaning that you should read its value using settings.value("comboBox/comboBox").toInt(). Also please note that you are calling settings.setValue only in the case where currentIndex changes to 2, are you sure you mean to do that? didn't you mean to call it after all your if/else blocks?
Upload file using wt
I am new to WT, i am trying the upload file example . The code works fine when i click the send button the file progress bar runs to 100% but i am not sure where it is uploaded ? can we define to upload in certain path.. class HelloApplication: public WApplication { public: HelloApplication(const WEnvironment& env); private: WPushButton *uploadButton; Wt::WFileUpload *fu; void greet(); }; HelloApplication::HelloApplication(const WEnvironment& env) : WApplication(env) { root()->addStyleClass("container"); setTitle("Hello world"); // application title fu = new Wt::WFileUpload(root()); fu->setFileTextSize(50); // Set the maximum file size to 50 kB. fu->setProgressBar(new Wt::WProgressBar()); fu->setMargin(10, Wt::Right); // Provide a button to start uploading. uploadButton = new Wt::WPushButton("Send", root()); uploadButton->setMargin(10, Wt::Left | Wt::Right); // Upload when the button is clicked. uploadButton->clicked().connect(this, &HelloApplication::greet); } void HelloApplication::greet() { fu->upload(); uploadButton->disable(); } WApplication *createApplication(const WEnvironment& env) { return new HelloApplication(env); } int main(int argc, char **argv) { return WRun(argc, argv, &createApplication); }
A WFileUpload will fire a signal (uploaded()) when the file is completed. Then look at spoolFileName() to get the filename of the file on your local disk. Listen on fileTooLarge() too, since it will inform you that the upload failed. The manual of WFileUpload comes with a lot of information and a code example: http://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WFileUpload.html
I realise this is an old post but I also had issues and the question wasn't quite answered (specifically the uploadedFiles function that is needed to read the contents of the file) In your constructor (i.e. the HelloApplication::HelloApplication function) add this to react to the fileUploaded signal: uploadButton->uploaded().connect(this, &HelloApplication::fileUploaded); Then add a function like this to read the contents of the file: void HelloApplication::fileUploaded() { //The uploaded filename std::string mFilename = fu->spoolFileName(); //The file contents std::vector<Wt::Http::UploadedFile> mFileContents = fu->uploadedFiles(); //The file is temporarily stored in a file with location here std::string mContents; mContents=mFileContents.data()->spoolFileName(); //Do something with the contents here //Either read in the file or copy it to use it //return return; } I hope this helps anyone else redirected here.