Greeting
Im trying to download file with QT 4.8 and VS 2008 but i cant, It fail all the time.
I use following code to download file from FTP server.
void FTP::download(QString strFileName, QString strFTPFileName)
{
QFile * file = new QFile(strFileName);
if (m_fFile->open(QIODevice::ReadWrite))
{
QString strFtpServerIPAddress("192.168.7.10");
QString strFtpServerPortNumber("21");
QString strFtpUserName("admin");
QString strFtpPassword("admin");
QString strFtpFolderPath("\outgoing\");
qint16 iFtpPort = 21;
QFtp * ftp = new QFtp();
connect(ftp, SIGNAL(stateChanged(int)),SLOT(onStateChanged(int)));
connect(ftp, SIGNAL(done(bool)),SLOT(onDone(bool)));
connect(m_objFtp, SIGNAL(commandFinished(int, bool)),SLOT(onCommandFinished(int, bool)));
int iConnectToHostID = ftp->connectToHost(strFtpServerIPAddress, iFtpPort);
int iLogInID = ftp->login(strFtpUserName, strFtpPassword);
int iChangeDirectoryID = ftp->cd(strFtpFolderPath);
QFileInfo fileInfo(strFTPFileName);
QString strFileNameOnly(fileInfo.fileName());
int iOperationID = ftp->get(strFileNameOnly, file);
QEventLoop loop;
connect(this, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
ftp->close();
file->close();
delete ftp;
}
}
void FTP::onDone(bool bError)
{
...
//If "id" (saved from onStateChanged) is equal to "iOperationID", I emit "finished" Signal
...
}
I was checking onCommandFinished slot and all steps (HostLookup, Connecting, Connected, LoggedIn) finish without error but exactly in get operation, error is true and when i get detail about error with following codes ,
string strReason = QFtp::errorString().toStdString();
int iError = QFtp::error();
strReason is Unknown error and iError is 0.
Any idea what is going wrong here ?
Thanks in advanced
EDIT 1
I found the problem. Some how i cant download file from root directory, If i try to download file inside another directory, It work.
In my code , I check if strFtpFolderPath is empty or equal to ".", In this case i change directory with ftp->cd("/") other wise i set it to given path.
Any idea why i cant download file from root directory?
Related
so I wrote a programm for my thesis in Qt and now i am supposed to turn it into a working web assembly, which wasnt a real problem except for the filedownload part. I rewrote my filedownload method from:
QString costumfile::read(QString filename){
QString fileName = QFileDialog::getOpenFileName(nullptr, filename, "", "Text Files (*.txt )");
QFile file(filename);
qDebug()<<filename<<"filename";
if(!file.open(QFile::ReadOnly |
QFile::Text))
{
qDebug() << " Could not open the file for reading";
return "";
}
QTextStream in(&file);
QString myText = in.readAll();
//qDebug() << myText;
file.close();
return myText;
}
To this:
QString costumfile::read(QString filename)
{
QMessageBox msgBox;
QString textUser="Open" + filename;
msgBox.setText(textUser);
msgBox.exec();
QString text="hallo";
qDebug()<<filename;
auto fileContentReady = [&](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
msgBox.setText("Error");
msgBox.exec();
} else {
text=fileContent;
qDebug()<<text<<"texstis";
return fileContent;
}
return fileContent;
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
and the problem is that the return doesnt wait for the lambda function because its asynch...
I then tried using eventloops which works fine in the Destop applikation but isnt supported in the webassembly Applikation.
So does someone have a good idea how to wait for the fileContentReady Function?
As far as I know, Qt for WebAssembly currently does not support waiting using event loops (at least Qt 6.2 does not). See Qt wiki:
"Nested event loops are not supported. Applications should not call e.g. QDialog::exec() or create a new QEventLoop object."
https://wiki.qt.io/Qt_for_WebAssembly
So you would have to modify your method to handle the asynchronous call. What I mean is that whatever you want to do with the file, you can write directly into the fileContentReady lambda you have. If this is a generic function, you can let the caller register a done callback to execute when the file is ready. Something like:
QString costumfile::read(QString filename,
const std::function<void(const QString&)>& done)
{
...
auto fileContentReady = [=](const QString &fileName, const QString &fileContent) {
if (fileName.isEmpty()) {
// Report error
} else {
text=fileContent;
qDebug()<<text<<"texstis";
done(text);
}
};
QFileDialog::getOpenFileContent(".txt", fileContentReady);
}
// When calling costumfile::read
read(filename, [=] (const QString& text) {
// Do something with `text`
});
Also, about the usage of QMessageBox exec(). This can also cause problems as it internally creates a nested event loop which is not yet supported in Qt for WebAssembly. Instead use the show() method.
auto msgBox = new QMessageBox();
msgBox->setText(textUser);
connect(msgBox, &QMessageBox::finished, &QMessageBox::deleteLater);
msgBox->show();
I am trying to use the following code to open the existing file to append data at it's end:
void AddPharmacyForm::addInsertToFile(QString insert)
{
QFile inserts(":/new/prefix1/insertstatements.txt");
if(!inserts.exists())
qDebug() << "File does not exist";
if(inserts.isOpen())
qDebug() << "file is open";
if(inserts.open(QFile::ReadWrite | QFile::Text))
{
// Another workaround- could not open file with append flag
qDebug() << "im here!";
QString currentInserts;
QTextStream out(&inserts);
out >> currentInserts;
out << endl << insert;
inserts.close();
}
else
{
QMessageBox::information(this, tr("Error"), tr("Cannot add new pharmacy! "
"Please contact program designer."
));
qDebug() << "error code: " + QString::number(inserts.error());
return;
}
}
The output of this code is the QMessageBox with the error and in qDebug it produces following line:
"error code: 5"
It does not give notice about file not existing and file being open. I have also tried opening file with different flags: QFile::ReadWrite, QFile::append, QFile::WriteOnly and the same modes within QIODevice. The error code is still the same. When I am opening the file from another class, the file opens without errors (it is not an access error).
What might be causing this problem?
There's no support for writing into the resource system, whether implemented using Qt's resource system or native to the platform. Your application typically has no right to modify its own executable, or the application bundle, or its installation location - it'd be a security risk if it did since bugs in networking code could be easily exploited to infect your user's system. So what you're trying to do is just a bad idea.
Instead, store the modified resources in your application's data folder, and revert to reading from the resource if the file doesn't exist. It is also probably not very wise to append to a file if the file is small: such appends are not atomic and can partially fail, leaving the file corrupted. Using a QSaveFile is guaranteed to either completely succeed or to fail without modifying any data.
An example implementation follows. The src.close() is not necessary to close the file, as QFile will automatically close upon destruction, as it is a proper resource-managing C++ class. By closing it earlier we ensure minimal use of the file descriptor - a finite system resource.
// https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#include <QtCore>
const char kInsertsFile[] = ":/insertstatements.txt";
QString toWritableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
QFileInfo info(qrcFileName);
return
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ info.path().mid(1) + '/' + info.fileName();
}
QString toReadableName(const QString & qrcFileName) {
Q_ASSERT (qrcFileName.startsWith(":/"));
auto writable = toWritableName(qrcFileName);
return QFileInfo(writable).exists() ? writable : qrcFileName;
}
bool setupWritableFile(QSaveFile & dst, QIODevice::OpenMode mode = {}) {
Q_ASSERT (dst.fileName().startsWith(":/"));
Q_ASSERT (mode == QIODevice::OpenMode{} || mode == QIODevice::Text);
QFile src(toReadableName(dst.fileName()));
dst.setFileName(toWritableName(dst.fileName()));
if (!src.open(QIODevice::ReadOnly | mode))
return false;
auto data = src.readAll();
src.close(); // Don't keep the file descriptor tied up any longer.
QFileInfo dstInfo(dst.fileName());
if (!dstInfo.dir().exists() && !QDir().mkpath(dstInfo.path()))
return false;
if (!dst.open(QIODevice::WriteOnly | mode))
return false;
return dst.write(data) == data.size();
}
bool addInsertToFile(const QString & insert) {
QSaveFile file(kInsertsFile);
if (!setupWritableFile(file, QIODevice::Text))
return false;
if (true) {
// Alternative 1
QTextStream s(&file);
s << insert << '\n';
} else {
// Alternative 2
file.write((insert + '\n').toLocal8Bit());
}
return file.commit();
}
QStringList readInserts() {
QFile file(toReadableName(kInsertsFile));
if (!file.open(QIODevice::ReadOnly))
return {};
return QString::fromLocal8Bit(file.readAll()).split('\n', QString::SkipEmptyParts);
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
app.setApplicationName("resource-bypass-42044268");
qDebug() << "Original Inserts:" << readInserts();
auto rc = addInsertToFile("NewInsert");
qDebug() << "Modification status:" << rc;
qDebug() << "Current Inserts:" << readInserts();
}
When you use the Qt Resource System (qrc files) to add files for your project, they are compiled directly into the binary of your application, so are therefore readonly. As the documentation states: -
Resource data can either be compiled into the binary and thus accessed immediately in application code, or a binary resource can be created and at a later point in application code registered with the resource system.
And...
Currently, Qt always stores the data directly in the executable, even on Windows, macOS, and iOS, where the operating system provides native support for resources. This might change in a future Qt release.
I am downloading an ".apk" file from a Url with Get method.
The file successfully donwload on my disk from the server.
I actually want to add a progressbar to my program. THE problem is : I can show the bytesReceived but I can't show the totalBytes of the file I am downloading (ContentLenth). How can I get it please from the server.
Here is what i get on my qDebug while downloading:
3498 of -1
799062 of -1
1923737 of -1
3037550 of -1
3200231 of 3200231
Here is my code:
void DownloadApk::LaunchDownload()
{
QNetworkProxy proxy;
proxy.setType(QNetworkProxy::HttpProxy);
proxy.setHostName("proxy");
proxy.setPort(8080);
QNetworkProxy::setApplicationProxy(proxy);
QUrl url("I put my Url here");
QNetworkRequest request(url);
_file = new QFile("C:/Users/Desktop/testdownload/downloadedFile.apk");
_file->open(QIODevice::WriteOnly);
QNetworkAccessManager *_manager= new QNetworkAccessManager;
_reply = _manager->get(request);// Manager is my QNetworkAccessManager
_file->write(_reply->readAll());
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateProgress(qint64, qint64)));
connect(_reply, SIGNAL(finished()),
this, SLOT(finished()));
}
void DownloadApk::error(QNetworkReply::NetworkError err)
{qDebug() << err;
// Manage error here.
_reply->deleteLater();
}
void DownloadApk::updateProgress(qint64 read, qint64 total)
{
qDebug() << read <<"of"<<total ;
QByteArray b = _reply->readAll();
QDataStream out(_file);
out << b;
}
void DownloadApk::finished()
{
QMessageBox::information(this, tr("Complete"), tr("Successfully Downloaded"));
// Done
_reply->deleteLater();
_file->close();
// probably delete the file object too
}
I fixed the problem. Actually it was not a QT problem. This Qt code works correctly.
The probleme was from the server that wasn't sending ContentLenth on the header of the reply.
This is how I am initializing the watcher:
QFileSystemWatcher watcher;
bool isWatched = watcher.addPath("../stylesheets/main.style");
if (isWatched) qDebug() << "Stylesheet is being watched.";
connect(&watcher, &QFileSystemWatcher::fileChanged, this, &PCLViewer::updateStyle );
But my update style function never gets called, when I modify, delete or rename the file! I've also tried connecting the slots and signals like this:
connect(&watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateStyle(QString)) );
The signature for the updateStyle functions is this:
public slots:
void updateStyle(const QString &path);
I'm using ubuntu.
If anyone is having the same problem.
Try this:
QFileSystemWatcher *watcher = new QFileSystemWatcher();
bool beingWatched = watcher->addPath("Enter your path here");
if (beingWatched ) qDebug() << "Being watched";
QObject::connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(handleFileChanged(QString)));
I don't know why but you need to create a pointer, at least on my system, to emit a signal or it won't work.
The slot function signature was wrong. I had to use void updateStyle (QString path); for it to get called.
I have a derived class from QObject that has a bunch of concatenated WAVE files in a QByteArray as a member variable.
I want to play specific files in that array (provided that I have the offset of it) through a QAudioOuput.
Here is the code of the PlaySound Method:
void DRMUtils::PlaySound(int offset){
mAudioFormat = new QAudioFormat(GetFormat(offset));
mAudioOut = new QAudioOutput(*mAudioFormat);
mBufferedAudio = new QBuffer();
mBufferedAudio->setData(GetSound(offset));
mBufferedAudio->open(QIODevice::ReadOnly);
connect(mAudioOut, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioStateChanged(QAudio::State)));
mAudioOut->start(mBufferedAudio);
}
I get the file format from the 44 first bytes (WAVE standard) with GetFormat(offset) and I get the data in QByteArray format with GetSound(offset)
Everything seems to work fine (I can hear the sample play), but the state of QAudioFormat never changes from "ActiveState"
Here is my slot code:
void DRMUtils::handleAudioStateChanged(QAudio::State newState)
{
qDebug() << "State: " << newState;
switch (newState) {
case QAudio::IdleState:
// Finished playing
mAudioOut->stop();
mBufferedAudio->close();
delete mAudioOut;
delete mBufferedAudio;
delete mAudioFormat;
qDebug() << "DELETED!";
break;
case QAudio::StoppedState:
// Stopped for other
qDebug() << "STOPPED!";
if (mAudioOut->error() != QAudio::NoError) {
// Error handling
qDebug() << "STOPPED ERROR!";
}
break;
default:
// ... other cases as appropriate
qDebug() << "DEFAULT!";
break;
}
}
My Debug output is always:
State: ActiveState
DEFAULT!
Do I have to "cap" the mBufferedAudio in some way that QAudioOutput "knows" when the sample is completed?
Also, I anybody can tell me when why when I initialize mAudioOut like this (declaring the parent):
mAudioOut = new QAudioOutput(*mAudioFormat, this);
instead of (not declaring the parent):
mAudioOut = new QAudioOutput(*mAudioFormat);
I don't get any output to the speakers (with parent declared).
Thanks
May be this gets deleted? So mAudioOut is deleted too when the parent is specified. It would also explain why you don't receive state changes (if the object gets deleted, the slot cannot be called anymore).