Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to properly call QFile::remove() on Windows?

How to properly call QFile::remove() on Windows?

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 6 Posters 451 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Robert Hairgrove

    @IgKh and @Kent-Dorfman : Thank you, this is very helpful information. My application does call QSqlDatabase::removeDatabase() on the connection before it tries to delete the file, but maybe I need to also call QApplication::processEvents()?

    The tip about calling GetLastError() is a good one in situations like this. I will test this again before marking it solved.

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote last edited by JonB
    #7

    @Robert-Hairgrove
    If you say you can literally put QFile::remove(x) where you have x.remove() and it works then I would look at/show what you exactly have done with your QFile.

    Also, assuming you are using QSqlDatabase, have you done what you're not supposed to do and kept a member variable copy of it?

    1 Reply Last reply
    0
    • Andy314A Offline
      Andy314A Offline
      Andy314
      wrote last edited by
      #8

      I had the same problem. Simple close() of the database solved it.

      JonBJ 1 Reply Last reply
      0
      • Andy314A Andy314

        I had the same problem. Simple close() of the database solved it.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote last edited by
        #9

        @Andy314
        Although I am sure this in itself is a useful recommendation, and may well solve the problem for whatever reason, did you really have the same problem where QFile file(...); file.remove(); failed while QFile::remove(...); succeeded? If so, do you have a repro? This is what is strange here. Because it seems like that would only be the case depending on what you had done with your QFile file instance....

        R 1 Reply Last reply
        0
        • JonBJ JonB

          @Andy314
          Although I am sure this in itself is a useful recommendation, and may well solve the problem for whatever reason, did you really have the same problem where QFile file(...); file.remove(); failed while QFile::remove(...); succeeded? If so, do you have a repro? This is what is strange here. Because it seems like that would only be the case depending on what you had done with your QFile file instance....

          R Offline
          R Offline
          Robert Hairgrove
          wrote last edited by
          #10

          @JonB and @Andy314 : Thanks for the feedback. I am pretty sure that the database connection is being handled properly. It is possible that it has to do with my environment ... running in Oracle VirtualBox in a Windows 10 guest on a Linux host. I had an issue once where I could not remove a USB stick in the virtual environment for several minutes because Windows thought it was being used, where it certainly wasn't. I don't have any anti-virus software running in the guest, but maybe it was just Windows doing its housekeeping?

          I need to look at the Qt source code some more ... if all else fails, I can try putting the call to QFile::remove() in a while loop and call std::yield or QApplication::processEvents().

          JonBJ 1 Reply Last reply
          0
          • R Robert Hairgrove

            @JonB and @Andy314 : Thanks for the feedback. I am pretty sure that the database connection is being handled properly. It is possible that it has to do with my environment ... running in Oracle VirtualBox in a Windows 10 guest on a Linux host. I had an issue once where I could not remove a USB stick in the virtual environment for several minutes because Windows thought it was being used, where it certainly wasn't. I don't have any anti-virus software running in the guest, but maybe it was just Windows doing its housekeeping?

            I need to look at the Qt source code some more ... if all else fails, I can try putting the call to QFile::remove() in a while loop and call std::yield or QApplication::processEvents().

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote last edited by JonB
            #11

            @Robert-Hairgrove
            In your sample code you just show:

                QFile x(absFilePath);
            
            #ifdef Q_OS_WINDOWS
                if (x.isOpen()) {
                  x.close();
                }
            #endif
            
                if (!x.remove()) {
            
            • Put in a debug, do you actually hit that x.close()?
            • Please show what you actually do with the QFile x in between creating the variable and the close for the attempted remove.

            Oh, and to be 100% clear, the absFilePath is the path to the actual database file on disk opened by QSqlDatabase, right?

            R 1 Reply Last reply
            0
            • JonBJ JonB

              @Robert-Hairgrove
              In your sample code you just show:

                  QFile x(absFilePath);
              
              #ifdef Q_OS_WINDOWS
                  if (x.isOpen()) {
                    x.close();
                  }
              #endif
              
                  if (!x.remove()) {
              
              • Put in a debug, do you actually hit that x.close()?
              • Please show what you actually do with the QFile x in between creating the variable and the close for the attempted remove.

              Oh, and to be 100% clear, the absFilePath is the path to the actual database file on disk opened by QSqlDatabase, right?

              R Offline
              R Offline
              Robert Hairgrove
              wrote last edited by
              #12

              @JonB said in How to properly call QFile::remove() on Windows?:

              @Robert-Hairgrove
              to be 100% clear, the absFilePath is the path to the actual database file on disk opened by QSqlDatabase, right?

              No ... absFilePath is the name of the file chosen by the user which will be the name of the new database. It just so happens that this is an existing file in this part of the code, which happens to be a database. There is no open database connection when this code runs, and there is nothing between the QFile x(...) statement and the #ifdef.... The application ensures that any open database is closed (i.e. the connection is removed) before letting the user create a new one.

              Like @IgKh said, it is pretty much what is in the Qt source code for QFile::remove() ... it also closes the file before trying to remove it. And if it isn't open, then I assume there is no need to call close(). But maybe I should not trust QFile::isOpen() and just call close() in any case?

              JonBJ 1 Reply Last reply
              0
              • R Offline
                R Offline
                Robert Hairgrove
                wrote last edited by
                #13

                Maybe this is overkill for something which should be very simple, but at least it is working.
                The code right before the following performs some checks on exisence and file permissions. If the user chooses to delete the file, then this part runs:

                  QString errstring;
                
                  if (delete_existing_file) {
                    std::chrono::microseconds us(0);
                    const std::chrono::microseconds us_begin(0);
                    const std::chrono::microseconds interval(500);
                    const std::chrono::microseconds max_wait(1000000);
                    { // start a new scope...
                      QFile x(absFilePath);
                      x.close();
                      // The following snippet taken from the example for std::this_thread::yield():
                      // https://en.cppreference.com/w/cpp/thread/yield.html
                      auto wait_for_remove = [](std::chrono::microseconds s) {
                        auto begin = std::chrono::high_resolution_clock::now();
                        auto end = begin + s;
                        do {
                          std::this_thread::yield();
                        } while(std::chrono::high_resolution_clock::now() < end);
                      };
                
                      while (!x.remove()) {
                        us += interval;
                        wait_for_remove(interval);
                        if (us >= max_wait)
                          break;
                      }
                      errstring = x.errorString();
                    } // x goes out of scope here...
                
                    if (us > us_begin) {
                      if (us < max_wait) {
                        // Success, but we waited at least once:
                        qDebug() << "Waited for QFile::remove() in microseconds: " << us;
                      } else {
                        title = tr("Problem Removing Existing File");
                        msg = tr("The file '%1' could not be removed.\n\nError message:\n%2")
                                .arg(absFilePath).arg(errstring);
                        QMessageBox::warning(this,title,msg);
                        qDebug() << "Failed to remove file: " << absFilePath << "Error: " << errstring;
                        return;
                      }
                    }
                  }
                
                R 1 Reply Last reply
                0
                • R Robert Hairgrove has marked this topic as solved
                • R Robert Hairgrove

                  @JonB said in How to properly call QFile::remove() on Windows?:

                  @Robert-Hairgrove
                  to be 100% clear, the absFilePath is the path to the actual database file on disk opened by QSqlDatabase, right?

                  No ... absFilePath is the name of the file chosen by the user which will be the name of the new database. It just so happens that this is an existing file in this part of the code, which happens to be a database. There is no open database connection when this code runs, and there is nothing between the QFile x(...) statement and the #ifdef.... The application ensures that any open database is closed (i.e. the connection is removed) before letting the user create a new one.

                  Like @IgKh said, it is pretty much what is in the Qt source code for QFile::remove() ... it also closes the file before trying to remove it. And if it isn't open, then I assume there is no need to call close(). But maybe I should not trust QFile::isOpen() and just call close() in any case?

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote last edited by JonB
                  #14

                  @Robert-Hairgrove said in How to properly call QFile::remove() on Windows?:

                  there is nothing between the QFile x(...) statement and the #ifdef....

                   QFile x(absFilePath);
                   x.close();
                  

                  Then I have no idea why you are creating any QFile instance here at all. And if for unknown reason it is causing problem just remove it, why have you put this in? Oh, did you say purely in order to be able to go x.remove() so that you can get QFile::error() information for message? Certainly you should not need the close(), and I asked earlier if your if (x.isOpen()) was ever true, because with this code it should never be?

                  Looks like we shall never know why this fails when the static call succeeds....

                  R 1 Reply Last reply
                  0
                  • JonBJ JonB

                    @Robert-Hairgrove said in How to properly call QFile::remove() on Windows?:

                    there is nothing between the QFile x(...) statement and the #ifdef....

                     QFile x(absFilePath);
                     x.close();
                    

                    Then I have no idea why you are creating any QFile instance here at all. And if for unknown reason it is causing problem just remove it, why have you put this in? Oh, did you say purely in order to be able to go x.remove() so that you can get QFile::error() information for message? Certainly you should not need the close(), and I asked earlier if your if (x.isOpen()) was ever true, because with this code it should never be?

                    Looks like we shall never know why this fails when the static call succeeds....

                    R Offline
                    R Offline
                    Robert Hairgrove
                    wrote last edited by Robert Hairgrove
                    #15

                    @JonB Here you can read the Qt6 source code of QFile::remove() ... the first link is to the non-static member function, and the second is to the static member function. My code does pretty much the same thing except for the "while {...}" loop I have written:

                    https://codebrowser.dev/qt6/qtbase/src/corelib/io/qfile.cpp.html#421
                    https://codebrowser.dev/qt6/qtbase/src/corelib/io/qfile.cpp.html#452

                    Does this help?

                    And since there is basically no difference in the actual code, as I said ... I do want to get the error message.

                    1 Reply Last reply
                    0
                    • R Robert Hairgrove

                      Maybe this is overkill for something which should be very simple, but at least it is working.
                      The code right before the following performs some checks on exisence and file permissions. If the user chooses to delete the file, then this part runs:

                        QString errstring;
                      
                        if (delete_existing_file) {
                          std::chrono::microseconds us(0);
                          const std::chrono::microseconds us_begin(0);
                          const std::chrono::microseconds interval(500);
                          const std::chrono::microseconds max_wait(1000000);
                          { // start a new scope...
                            QFile x(absFilePath);
                            x.close();
                            // The following snippet taken from the example for std::this_thread::yield():
                            // https://en.cppreference.com/w/cpp/thread/yield.html
                            auto wait_for_remove = [](std::chrono::microseconds s) {
                              auto begin = std::chrono::high_resolution_clock::now();
                              auto end = begin + s;
                              do {
                                std::this_thread::yield();
                              } while(std::chrono::high_resolution_clock::now() < end);
                            };
                      
                            while (!x.remove()) {
                              us += interval;
                              wait_for_remove(interval);
                              if (us >= max_wait)
                                break;
                            }
                            errstring = x.errorString();
                          } // x goes out of scope here...
                      
                          if (us > us_begin) {
                            if (us < max_wait) {
                              // Success, but we waited at least once:
                              qDebug() << "Waited for QFile::remove() in microseconds: " << us;
                            } else {
                              title = tr("Problem Removing Existing File");
                              msg = tr("The file '%1' could not be removed.\n\nError message:\n%2")
                                      .arg(absFilePath).arg(errstring);
                              QMessageBox::warning(this,title,msg);
                              qDebug() << "Failed to remove file: " << absFilePath << "Error: " << errstring;
                              return;
                            }
                          }
                        }
                      
                      R Offline
                      R Offline
                      Robert Hairgrove
                      wrote last edited by
                      #16

                      @Robert-Hairgrove said in How to properly call QFile::remove() on Windows?:
                      Small correction:

                      if (us < max_wait) {
                      // Success, but we waited at least once:
                      qDebug() << "Waited for QFile::remove() in microseconds: " << us.count(); // <== need to use ".count()" here...
                      } else {
                      // etc.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved