Implement an auto update system

2 Comments

3. Download the new files to replace existing files

Now we start downloading all the files in the download list and have the old ones replaced. But here we will encounter a problem, you cannot modify the files that are currently being used. In other words, you cannot overwrite the old files with the new ones directly since your application is still running. Here is a simple trick. You cannot overwrite them, but you can rename them. So the function will:

  1. Create tmp folder to store the newly downloaded files
  2. Create a folder with current version number to backup the old files
  3. Rename the old files with .old extensions
  4. Copy over the files in tmp
void GUI::self_update_download(int i) {
	// Create a temporary folder
	if(!QFile::exists("tmp"))
		system("mkdir tmp");
 
	if(i < filelist.size()){
		QUrl url("http://address_to_files/"+latest_version+"/"+filelist[i]);
		QFileInfo fileInfo(url.path());
		QString fileName = "tmp/" + fileInfo.fileName();
		//QString fileName = fileInfo.fileName();
 
		if (QFile::exists(fileName)) {
			if (QMessageBox::question(this, tr("HTTP"),
				tr("There already exists a file called %1 in "
				"the current directory. Overwrite?").arg(fileName),
				QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel)
				== QMessageBox::Cancel)
				return;
			QFile::remove(fileName);
		}
 
		file = new QFile(fileName);
 
		if (!file->open(QIODevice::WriteOnly)) {
			QMessageBox::information(this, tr("HTTP"),
				tr("Unable to save the file %1: %2.")
				.arg(fileName).arg(file->errorString()));
			delete file;
			file = 0;
			return;
		}
 
		QHttp::ConnectionMode mode = url.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp;
		dhttp->setHost(url.host(), mode, url.port() == -1 ? 0 : url.port());
 
		QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/");
		if (path.isEmpty())
			path = "/";
		getRequestId = dhttp->get(path, file);
	}
	else if(filedownloaded == filelist.size() && filedownloaded != 0){
		QDir dir;
		// Create a new dir for current version for backup purposes
		if(!QFile::exists(this->VERSION))
			system(("mkdir "+this->VERSION).toStdString().c_str());
		// Backup old files and rename them
		for(int i=0; i<filelist.size(); i++){
			system(("copy "+filelist[i]+" "+this->VERSION+""+filelist[i]+" /Y").toStdString().c_str());
			dir.rename(filelist[i], filelist[i]+".old");
		}
		system("copy tmp*.* . /Y");
		system("rmdir tmp /S /Q");
 
		QMessageBox::information(this, tr("Update Sucess"), tr("Please restart App for updates to take effect."));
	}
 }
 
void GUI::self_update_complete(int requestId, bool error){
	if(requestId != getRequestId)  {
		return;
	}
	file->close();
 
	if (error) {
         file->remove();
         QMessageBox::information(this, tr("HTTP"),
                                  tr("Download failed: %1.")
                                  .arg(dhttp->errorString()));
	} else {
		 filedownloaded++;
	}
 
	delete file;
	file = 0;
	self_update_download(filedownloaded);
}

You may have noticed I used a lot of system() calls. I know, I know, I am just being lazy. You can replace them all with appropriate QT functions easily.

Pages: 1 2 3 4

RSSSubscribe to the RSS feed to receive more useful tips. Filed under: How-To,Programming

2 Responses to “Implement an auto update system”

  1. kaleem ullah khan
    April 29th, 2009 at 3:15 AM

    Hi Roland, I like the article, I have a small concern i am a C # developer, so i was looking at the code not very througly, I could not understand a part ,
    I understood that we created a temp folder and downloaded latest files in them, we also copied all current files to a new folder for backup how can i rename the current files to .old extension these files are already in use and also how i am going to tell my icon for instance to load from temp folder where new files are present.

    thanks

  2. rolandli
    April 29th, 2009 at 10:01 AM

    Hi Kaleem,

    I’m not too familiar with C#, but I will try my best to answer your question.

    Files which are in use cannot be deleted, but they can be renamed. In the example above, there is a vector filelist that stores a list of files to be updated. So just loop through it to and rename all the existing files in it.

    As far as I know, there is a function in C# is good for this purpose: System.IO.File.Move(@”C:\From.txt”, @”C:\TO.txt”);. Use it to add “.old” to all the existing files.

    After that, you can copy the newly downloaded files into the working folder since there is no file overwriting issue.

    In order for the new files to take effect, the program MUST be restarted. And in your main loop, before anything else take place, check if the working folder has any “.old” file, if so, delete them all.

    I hope that answers your question.

Leave a comment