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. C++ Qt QFileSystemWatcher file upload double

C++ Qt QFileSystemWatcher file upload double

Scheduled Pinned Locked Moved General and Desktop
2 Posts 1 Posters 1.1k Views
  • 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.
  • S Offline
    S Offline
    Sk1F0x
    wrote on 23 Aug 2013, 04:19 last edited by
    #1

    I am having issues where the file is being uploaded twice to the server.

    I am using the QFileSystemWatcher class from C++ Qt on Windows XP to send a file when the folder changes The files are small (1-12kb).

    The application sends the files by scanning the folder whenever it changes (on directoryChanged signal), loop through the files and send the one that I need. The server responds with an xml file that is returned into the same folder for another application to processes it.

    Apparently what’s happening is that on some systems there are 2 very fast directoryChanged signals at nearly the same time and there are two very fast file uploads happening.

    The server is running Apache and PHP, and there’s a simple MUTEX in place on the PHP side, but I just wanted to get to the root of the problem which seems to be on the Qt side. I'm open to using another class, another library or straight C++.

    Here is some code, I stripped all the irrelevant content:
    @this->w = new QFileSystemWatcher();
    this->w->addPath("C:/POSERA/MaitreD/DATA/INT");

    QStringList directoryList = w->directories();
    Q_FOREACH(QString directory, directoryList)
    qDebug() << "Watching Main Directory name: " << directory << endl;

    DirectoryWatcher* dw = new DirectoryWatcher;

    QObject::connect(
    this->w, SIGNAL(directoryChanged(const QString&)),
    dw, SLOT(directoryChanged(const QString&))
    );@

    1 Reply Last reply
    0
    • S Offline
      S Offline
      Sk1F0x
      wrote on 23 Aug 2013, 04:20 last edited by
      #2

      and the DirectoryWatcher.cpp:
      @DirectoryWatcher::DirectoryWatcher(QWidget* parent) : QWidget(parent)
      {
      lockSend = false;
      }

      void DirectoryWatcher::directoryChanged(const QString& str) {

      directoryLastChanged = str;
      
      QByteArray byteArray = str.toUtf8();
      const char* cString = byteArray.constData();
      
      sendChangedFiles(cString);
      

      }

      void DirectoryWatcher::sendChangedFiles(const char* path) {

      DIR *dir;
      struct dirent *ent;
      if ((dir = opendir (path)) != NULL) {
      
          QString str;
      
          while ((ent = readdir (dir)) != NULL) {
              str = QString("%1/%2").arg(path, ent->d_name);
      
              QFileInfo info(str);
      
      
      
              if (lockSend == false && (info.completeSuffix() == "xml" || info.completeSuffix() == "XML") && info.baseName() != "" && !info.baseName().startsWith("REDM") && !info.baseName().startsWith("REFT")) {
      
                  // reset the counter.
                  this->resendCounter = 0;
      
                  sendFileAndAccept(str.toUtf8().constData());
      
              }
      
          }
      
          closedir (dir);
      } else {
          qDebug() << "Could not open directory" << endl;
      }
      

      }

      class QNetworkRequest;
      class QNetworkReply;
      void DirectoryWatcher::sendFileAndAccept(const char* path) {

      // increment the resend counter
      this->resendCounter++;
      
      QFileInfo fileInfo(path);
      
      QNetworkAccessManager * mgr = new QNetworkAccessManager(this);
      connect(mgr,SIGNAL(finished(QNetworkReply*)),this,SLOT(saveResponse(QNetworkReply*)));
      connect(mgr,SIGNAL(finished(QNetworkReply*)),mgr,SLOT(deleteLater())); // @todo delete later
      
      QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
      
      QHttpPart filePart;
      filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/xml")); // @todo test
      filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"someFile\"; filename=\"" + fileInfo.baseName() + ".xml\""));
      
      currentFileSent = fileInfo.baseName();
      
      QFile *file = new QFile&#40;path&#41;;
      file->open(QIODevice::ReadOnly);
      filePart.setBodyDevice(file);
      file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
      
      multiPart->append(filePart);
      
      // POST request
      QNetworkReply *reply = mgr->post(QNetworkRequest(QUrl(XXXXXX)), multiPart);
      
      multiPart->setParent(reply); // delete the multiPart with the reply
      
      // lock
      lockSend = true;
      

      }

      void DirectoryWatcher::saveResponse(QNetworkReply *rep) {

      // get the response
      QByteArray bts = rep->readAll();
      QString str(bts);
      
      // compute new path
      QString partName = currentFileSent.mid(1, currentFileSent.length());
      QString newPath = QString("%1/A%2.xml").arg(directoryLastChanged, partName);
      
      qDebug() << "new path: " << newPath << endl;
      
      switch (rep->error()) {
          case QNetworkReply::NoError: {
              qDebug() << "NO ERROR" << endl;
      
              // save response to a file.
      
              QFile file&#40;newPath&#41;;
              file.open(QIODevice::WriteOnly | QIODevice::Text);
              QTextStream out(&file);
              out << str;
      
              file.close();
      
              break;
          }
          default:
      

      // case QNetworkReply::TimeoutError :
      // case QNetworkReply::HostNotFoundError :
      qDebug() << "NETWORK REPLY ERROR" << endl;
      // resend the file if the counter is < 10
      if (this->resendCounter < 5) {

                  // delay by n sec
                  QTime dieTime = QTime::currentTime().addSecs(1);
                  while( QTime::currentTime() < dieTime )
                      QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
      
                  sendFileAndAccept(this->lastPathSent.toStdString().c_str());
              } else {
      
                  // after 10 attempts, we're probably sure that the network is down
                  // save the file somewhere and generate a default one to prevent timeouts.
      
                  qDebug() << "Saving file for later..." << endl;
                  if (!saveFileForLater(lastPathSent.toStdString().c_str())) {
                      qDebug() << "ERROR SAVING FILE, CHECK IF FOLDER EXISTS AND THE PERMISSIONS." << endl;
                  }
      
                  // generate a default one to prevent timeouts.
                  qDebug() << "Generate a default file..." << endl;
                  // ...
              }
      
              break;
      }
      
      // unlock
      lockSend = false;
      
      rep->deleteLater(); // prevent memory leak
      

      }

      bool DirectoryWatcher::saveFileForLater(const char* pathToRequestFile) {

      QFile file&#40;pathToRequestFile&#41;;
      if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
          qDebug() << "readonly and text" << endl;
          return false;
      }
      
      QString path(pathToRequestFile);
      QFileInfo fileinfo(path);
      
      QString newPath = "C:\\data\\offline\\" + fileinfo.fileName();
      
      return file.copy(newPath);
      

      }@

      1 Reply Last reply
      0

      1/2

      23 Aug 2013, 04:19

      • Login

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