파일이 서버로 두 번 업로드되는 문제가 있습니다.C++ Qt QFileSystemWatcher 파일이 두 번 업로드됩니다.
Windows XP에서 C++ Qt의 QFileSystemWatcher 클래스를 사용하여 폴더가 변경 될 때 파일을 보냅니다. 파일 크기가 작습니다 (1-12kb).
응용 프로그램은 폴더가 변경 될 때마다 (directoryChanged 신호에서) 폴더를 검색하여 파일을 보내고 파일을 반복하여 필요한 파일을 보냅니다. 서버는 처리 할 다른 응용 프로그램의 동일한 폴더로 반환되는 XML 파일로 응답합니다.
분명히 어떤 시스템에서는 거의 동시에 2 개의 매우 빠른 directoryChanged 신호가 있고 두 개의 매우 빠른 파일 업로드가 발생합니다.
서버가 아파치와 PHP를 실행 중이고 PHP쪽에 간단한 MUTEX가 있지만 Qt 측에있는 것 같은 근본 원인을 찾고 싶습니다. 다른 클래스 나 다른 라이브러리 또는 스트레이트 C++를 사용할 수 있습니다. 당신의 도움을
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(path);
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(newPath);
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(pathToRequestFile);
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);
}
감사 :
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&)));
과 DirectoryWatcher.cpp : 여기
내가 모든 관련이없는 내용을 제거, 일부 코드이다.
나는 해결책을 찾을 수 있을지 의심 스럽다. 이 행동을 확인할 수 있습니다. 나는 큰 파일 (> 500mb)을 가지고 있었지만. 파일 시스템 워처가 복사 프로세스 중에 여러 번 실행되었습니다. 또한 일종의 '뮤텍스 (mutex)'를 구현해야했습니다. 그러나 나는 너와 같은 작은 파일들로 그것을 볼 수있는 것이 조금 아직도 궁금하다. – Greenflow
나는 그 질문을 이해하지 못한다. 두 파일 모두에 대해 단 하나의 directoryChanged 신호 만 원하십니까 (알려진 클럭에 스로틀을 구현하십시오). 또는 각 파일을 개별적으로 처리 하시겠습니까? – rileyberton
답장을 보내 주셔서 감사합니다. @Greenflow 나는 그것이 반대라고 생각합니다. 작은 파일은 파일 업로드 시나리오에서 오류가 발생하기 쉽습니다. –