Releasing file lock in Qt - c++

I have a Qt program that works on Linux but not on Windows. It progressively downloads something from the internet, writes that into the file, and then tries to open that file using QDesktopServices::openUrl. This works fine under Linux (Fedora), but when I run under Windows, nothing happens - the file is never opened, but also no error is reported.
However if I try to manually open the downloaded file on Windows, I find the reason for this. I get the error Another program is currently using this file, meaning that Qt has not released its lock on the file. However I have already called file->close() on it.
How can I ensure that all locks on a QFile have been released?
Here's a fragment of code that runs after the file has been written:
QString filename = file->fileName();
if (!file->flush())
emit error("Could not finish writing file") // Not emitted
file->close();
QDesktopServices::openUrl(QUrl::fromLocalFile(filename));

I don't think this is a Qt issue. I have seen similar behaviour on Windows systems before (with and without Qt), it might be that either the CRT or the OS still haven't finished their work on the file.
You might try to disable disk write caching in the OS to see, if things work as expected. I had to do this in a Windows-Embedded RT environment to get deterministic behaviour.
BTW: You can evaluate QFile::error() even after calling QFile::close() so you can skip your flush part completely.

Related

File read after call to system()

My C++ program calls another program via system(). That program writes out to a file. I can't modify the called program.
My program then needs to read in the file that was written. At the present, my program reads in the file so quickly that the changes by the other program haven't yet hit the file system, and my program reads in an outdated version.
How can I force the called program to finish writing before my program tries to read? Or perhaps how can the calling program check that the file is finished being written?
I switched to system() from fork/execv and CreateProcess specifically so the program would block and I wouldn't have to watch for termination. So, I could switch back if that would help.
Right now, my only idea would be to delete the file before calling system() -- that way it wouldn't exist unless writing had completed.
Any solution needs to have versions for Mac, Windows, and Linux.
you should use wait() method to implement this. wait method make the parent process wait and sleeps it until its child process finishes. you should use fork() and then exec the another copy of process generated.
As far as I know if you try to open the file not in reading mode but in writing mode it will fail if the file is already being written by another process.
I would suggest to have a small (a few milliseconds) wait time to make sure the file was opened by the other process and then try to write on it and when you can actually write on the file then you can read it.
I'm not sure how things work on Mac but I assume it would be the same as Linux and Windows here.
It would be much better to use fork and exec instead of system so my suggestion is just a simple way (but not recommended for an important project) to go around the problem.

QFile / QTextStream don't show error on delete file being written to

I am writing to a QFile using a QTextStream, and all works great. I'm trying to create some error detection, so I tried deleting the output file between writes.
Strangle, Qtextstream's status continues to show 0 (no error), and QFile's error method returns 0. yet the file is gone, and text written is being lost...gone
What's going on? How can I detect the failure to write? Am I looking at the wrong methods?
Not sure about Windows, but on Linux and most Unix-type systems, the scenario you describe is simply not an error at all from the OS's point of view - it's perfectly legal to continue writing to a file that has been deleted (and it "works", data is still shuffled to/from the filesystem - this file is still there in the filesystem until the last handle to it is closed).
(I believe that on Windows you'll get an error if you try to delete the file while it's in use, at least if it was open with the default open mode - not 100% sure though.)
If you need to check for "file deleted", you'll need to write those checks yourself.

How do I start an external process using Qt?

FINAL EDIT: The code I've written below works, so disregard everything I've written. It seems that when I copied my input text file to the build directory, the file was somehow corrupted in process, which caused my external executable "prog" to break. Sorry for wasting your time and thanks to all of you who tried to help!
I've just started messing around with Qt and have a project called test_tiny. In the build folder of my project (where executable test_tiny is located), I have moved another little C++ executable called "prog" which reads from a file, does its thing, and outputs to a different file. The input file is also in the build directory.
I also have a window with a couple of text boxes and a few buttons. I would like to run my external program "prog" by pressing one of these buttons. This is what I've got so far:
void MainWindow::load2() {
QProcess *process = new QProcess(this);
process->start("./prog");
qDebug() << process->exitCode();
ui->textBrowser_2->clear();
ui->textBrowser_2->insertPlainText(read(":/File/out.txt"));
}
The second part works just fine - it reads from the out.txt file and loads it into the text browser. However, my process doesn't seem to run, and exitCode() always returns zero (I have changed it to 100 in "prog").
From what I've understood, the QProcess' working directory (unless otherwise specified) is set to its build folder, so calling process->start("./prog"); should work, but it doesn't. I've also tried calling it by referencing a QResource as well as giving the full path, but to no avail.
Any help would be appreciated, thanks!
I'm using Qt Creator 2.81 based on Qt 5.1.1 running on x64 Ubuntu 12.04.
EDIT: I forgot to mention that the executable "prog" only parses a few lines of text and outputs them to a file, which is then read and output to a text box. The external program "prog" doesn't actually seem to run, and I've already tried using process->waitForFinished().
You must wait till the process is finished before you check the exit code. You can wait by using the finised() signal or waitForFinished(). After waitForFinished succeeds or the finished signal is emitted it is safe to check the exit code. I almost always will use the finshed signal. However you should also make sure that the process started in the first place. Using the error() signal is how I detect if there is a problem starting the process. QProcess will emit this with a code describing the error. QProcess::FailedToStart will tell you that your application did not start in the first place.
You have two problems:
Are you on the correct path? while debugging using a full path, it make life easier.
You need to call QProcess::waitForFinished(LARGE_TIME) or connect to the finished() signal before you can check the error (the app starts asynchronously).

fopen vs ofstream

I'm having a strange issue that I think I have a workaround for, but I'm trying to do a root cause analysis on.
I've been developing an application that runs on an embedded version of Ubuntu 10.04 LTS. When the application starts up, it reads in a config file off of an SD card, initializes a few classes, starts a logger which writes to the SD card, and then proceeds with it's operation. During development, it has been running fine when I start it manually through an SSH terminal.
I've recently been experimenting with having the application start automatically when the OS starts up. I have a script in init.d which does just that. However, I noticed that no log files are being generated now. I figured out it's not a problem with the SD card not being available because the config file gets read properly on startup, but an error is thrown when I attempt to open the log file for writing using fopen.
// Open the file
mLogFile = fopen(filename, "wb");
if(mLogFile == NULL)
{
printf("Error opening Log File [%d].\n", lnRetval);
return -1; //File couldn't be opened
}
I assumed it was just a permissions problem, but I can't understand why it doesn't work when I automatically start the software versus running it manually in a terminal. Furthermore, I can't understand why the config file gets read in properly but this file can't be opened.
The only difference I could see was that the config file reading is done using fstreams, while the logger is using C file I/O. So I experimented by placing the following code directly before the fopen call above (/home/root/etc is where the SD card is mounted).
std::ofstream out("/home/root/etc/log/testlog.log");
out << "I can write using fstreams.\n";
out.close();
That worked and generated the file when started through init.d. Now I'm completely stumped. Why does ofstream work and not fopen? Is there something fundamentally I'm missing?
Thanks in advance.
Your question does not provide enough information to answer, but the general approach to problems like this should be to run the program (in both forms) under strace and compare the sequence of syscalls made. That should quickly reveal what's happening differently. I suspect you'll just find the contents of filename are invalid...

Export a .sqlite file in C/C++ (on windows)

It is possible to move a .sqlite file somewhere while not corrupting it in C or C++?
Somewhere could be another folder or something.
If so could you give me some tips/pointers.
Yes, of course. It is a regular file that can be moved around just like any other file.
The sqlite engine itself will make sure that it does not corrupt. Either it is in a clean state, or locked when being written to (with journaling).
One thing to remember that you should not use the database file on filesystems that do not have reliable locking, e.g. on network disks.
Well, it depends a little. It is just a regular file that (assuming nothing is connected to it, writing to it at the time) can be copied without problem. Welcome to the world of open source systems where things really are that simple (ie you don't need to update the registry, a config file or two, reapply installer settings or anything like that).
However, things are tricky if something is using the file. When an app opens a sqlite file it can tell the OS to lock it - the default is open with exclusive access for the opening app (using a certain flag). In such a case, you will not be able to move the file as the OS will prevent it until the app that has it locked is stopped.