I've got a problem with QFtp. I wanna download a single .txt file with a single line(8 bytes) from my server, so I've written the following code, but it doesn't work.
The file "actions.txt" were created in the folder1 directory. I can see the size of it pretty well in the client-side. But the file is not being written. I'm getting an empty file.
QFile* actionFile = new QFile("action.txt");
QFtp *ftp = new QFtp(parent);
void Dialog::getActionFile()
{
actionFile->open(QIODevice::WriteOnly);
ftp->connectToHost("mydomain.de");
ftp->login("user", "pw");
ftp->cd("folder1");
ftp->get("action.txt",actionFile);
ftp->close();
actionFile->close();
}
Thanks in advance.
The documentation of several methods of QFtp says:
The function does not block and returns immediately. The command is
scheduled, and its execution is performed asynchronously. The function
returns a unique identifier which is passed by commandStarted() and
commandFinished().
So you need to wait for the appropriate signals to be emitted.
Note that you can also use QNetworkRequest to request the whole ftp URL (I think even with username and password inside the URL) to download the file.
I solved my problem.
I treated one step each time the commandFininshed signal was emitted.
like this:
void MainWindow::ftpCommandFinished(int id, bool error)
{
static bool flag = false;
if(ftp->currentCommand() == QFtp::ConnectToHost)
checkUpdate();
if(ftp->currentCommand() == QFtp::Get)
{
file->close();
if(error)
{
QMessageBox::warning(this, "Erro!", ftp->errorString());
deleteLater();
return;
}
if(!flag)
checkVersion();
else{
delete ftp, file;
ftp = 0; file = 0;
}
flag = true;
}
}
the reason of the flag variable is something else that needs further explanations about the program, so i won't go down that road.
Thanks for you help. It somehow helped me a lot.
Related
I have problem with WebSocketPP Server. I want it to handle multiple clients.
Here is my OnOpen method:
void Server::onOpen(
Server* srv,
WSServer* ws,
websocketpp::connection_hdl& hdl)
{
ServerPlayerTracker con;
con.con = &hdl;
con.protocolVersion = 0;
con.verified = false;
con.playerID = srv->playerCount++;
con.roomID = 0;
srv->players.push_back(con);
}
But in disconnection i have problem. I cant find what player with ID disconnected. Here is my OnClose method:
void Server::onClose(
Server* srv,
WSServer* ws,
websocketpp::connection_hdl& hdl)
{
for (int i = 0; i < srv->players.size(); i++)
{
if (srv->players[i].connected)
{
if ((*srv->players[i].con).lock() == hdl.lock())
{
printf("[!] Player disconnected with ID: %d\n",
srv->players[i].playerID);
srv->players.erase(srv->players.begin() + i);
}
}
}
}
In line (*srv->players[i].con).lock() == hdl.lock() it throws exception like
'this was 0xFFFFFFFFFFFFFFF7.' in file 'memory' line 75. I think it's problem with converting weak_ptr to shared_ptr. Is there any way to fix that?
My comments seemed enough to fix the problem (see comments).
For future reference and to indicate that this problem has been answered, I have created this answer.
I'm not 100% sure what is (or is not) working in your current code, since it's quite different from the way the connections are stored and retrieved within the example code (See websocketPP github/documentation example "associative storage").
Using the example, it should be rather easy to set up a multiple client structure, in the way it was intended by the library creator.
For your specific error, I believe you're on the right track about the shared/weak pointer conversion.
Best solution would be to use the list in the way it's used in the example.
Especially interesting is the "con_list" which saves all connections.
It's a typedef of std::map<connection_hdl,connection_data,std::owner_less<connection_hdl>> con_list; con_list m_connections; and should enable you to store and retrieve connections (and their session data).
As part of a music player I am developing with C++/Qt, I am scanning all audio files with taglib to get the metadata for the database.
I noticed something interesting.
The first time after a restart, it takes about 100ms and 500ms on my system to create a TagLib::FileRef object. When I use the same file again to create a TagLib::FileRef it takes 0ms, even after I restart the musicplayer.
Here is the function I am using to test that:
bool suffixCheck(const QString &val)
{
if (val.endsWith(".mp3")) {
return true;
}
if (val.endsWith(".m4a")) {
return true;
}
if (val.endsWith(".ogg")) {
return true;
}
return false;
}
void doTaglibThing(const QString &path)
{
if (suffixCheck(path)) {
QElapsedTimer timer;
timer.start();
TagLib::FileRef f(path.toUtf8().data(),
true,
TagLib::AudioProperties::Accurate);
Q_UNUSED(f);
qDebug() << "End taglibThing" << timer.elapsed();
}
}
Why is this? I assume that taglib somehow "remembers" the objects. How can I make it so that taglib doesn't remember and always actually has to read the file.
I want to optimize the library scanning function and I don't always want to restart the whole system to check how changes to the code impact the first-run scan.
As suggested by Frank Osterfeld, the file data was still in disk cache.
Clearing the disk cache with
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
makes taglib re-read the file from the disk again.
How could I use QuaZip to extract a .zip file and show its extraction progress in a QProgressDialog?
I've tried an example from this question1 (and also this question2) without success. Because I need to unzip .zip files (not .gz files) and that code shows % of progress but not unzip the files.
And even that, I don't know how to show that % in a QProgressDialog.
I've been able to extract .zip file using:
JlCompress::extractDir("C:/test/test.zip", "C:/test/");
However, that is not enought for my goal, because I need to show that extraction progress in a QProgressDialog in real time...
This is my code:
QString fileName = "C:/test/firefox-29.0.1.gz"; //I need to unzip .zip files
qDebug() << "Opened";
progressUnzip->setWindowTitle(tr("Unzip Manager"));
progressUnzip->setLabelText(tr("Unzipping %1. \nThis can take a long time to complete").arg(fileName));
progressUnzip->setAttribute(Qt::WA_DeleteOnClose);
QFile file(fileName);
file.open(QFile::ReadOnly);
QuaGzipFile gzip;
gzip.open(file.handle(), QuaGzipFile::ReadOnly);
progressUnzip->show();
while(true) {
QByteArray buf = gzip.read(1000);
//process buf
if (buf.isEmpty()) { break; }
QFile temp_file_object;
temp_file_object.open(file.handle(), QFile::ReadOnly);
double progress = 100.0 * temp_file_object.pos() / file.size();
updateUnzipProgress(temp_file_object.pos(), file.size());
qDebug() << qRound(progress) << "%";
}
unzipFinished();
qDebug() << "Finish";
Where:
void MainWindow::updateUnzipProgress(qint64 bytesRead, qint64 totalBytes)
{
qDebug() << bytesRead << "/" << totalBytes;
qint64 th = 1;
if (totalBytes >= 100000000)
{
th = 1000;
}
progressUnzip->setMaximum(totalBytes/th);
progressUnzip->setValue(bytesRead/th);
}
// When unzip finished or canceled, this will be called
void MainWindow::unzipFinished()
{
qDebug() << "Unzip finished.";
progressUnzip->hide();
}
In this code, QProgressDialog doesn't show any progress bar and at the end the file is not unzipped.
Any idea?
Thanks for your help,
I'm not going to write the whole code for you, but I can give you some hints to help you solve the problem.
QuaZIP library does not provide any Qt signals about the extraction progress, and that means that you should implement it yourself.
First, take a look at JlCompress::extractDir function implementation to see how it works. The source code can be found here. The function creates a QuaZip object which describes the zip archive you want to extract. Then it iterates over the files in the archive. On every iteration it creates a QuaZipFile object which describes a compressed file in the archive and then writes (=extracts) its data to a new file.
This is the copy function:
static bool copyData(QIODevice &inFile, QIODevice &outFile)
{
while (!inFile.atEnd()) {
char buf[4096];
qint64 readLen = inFile.read(buf, 4096);
if (readLen <= 0)
return false;
if (outFile.write(buf, readLen) != readLen)
return false;
}
return true;
}
inFile is the compressed (QuaZipFile) file and outFile is a new file where the compressed data is extracted to.
Now you should understand the underlying logic.
To add signals about extraction progress, you can can copy the JlCompress::extractDir source code to some wrapper class and make some changes.
While iterating over the files in the archive, you can get information about them using QuaZipFile::getFileInfo. That information contains uncompressed file size. Now go back to the copyData function. You know how many bytes you have written and you know the expected file size. That means you can calculate the single file extraction progress. Also you can get total files count and their uncompressed sizes using QuaZip::getFileInfoList64. That will let you calculate the whole extraction progress too.
How may I download a file in C++ with wxWidgets?
Been googling and everything and nothing shows up! Help appreciated!
Use wxHTTP class for that.
wxHTTP Example Code:
#include <wx/sstream.h>
#include <wx/protocol/http.h>
wxHTTP get;
get.SetHeader(_T("Content-type"), _T("text/html; charset=utf-8"));
get.SetTimeout(10); // 10 seconds of timeout instead of 10 minutes ...
while (!get.Connect(_T("www.google.com")))
wxSleep(5);
wxApp::IsMainLoopRunning();
wxInputStream *httpStream = get.GetInputStream(_T("/intl/en/about.html"));
if (get.GetError() == wxPROTO_NOERR)
{
wxString res;
wxStringOutputStream out_stream(&res);
httpStream->Read(out_stream);
wxMessageBox(res);
}
else
{
wxMessageBox(_T("Unable to connect!"));
}
wxDELETE(httpStream);
get.Close();
If you want more flexible solution consider using libcurl.
Depends on where you want to 'download' it from, and how the file server allows files to be downloaded. The server might use FTP, or HTTP, or something more obscure. There is no way to tell from your question which has no useful information in it.
In general, I would not use wxWidgets for this task. wxWidgets is a GUI frmaework, with some extras for various things that may or may not be helpful in your case.
From HTTP as Andrejs suggest, from FTP using wxFTP
wxFTP ftp;
// if you don't use these lines anonymous login will be used
ftp.SetUser("user");
ftp.SetPassword("password");
if ( !ftp.Connect("ftp.wxwindows.org") )
{
wxLogError("Couldn't connect");
return;
}
ftp.ChDir("/pub");
wxInputStream *in = ftp.GetInputStream("wxWidgets-4.2.0.tar.gz");
if ( !in )
{
wxLogError("Coudln't get file");
}
else
{
size_t size = in->GetSize();
char *data = new char[size];
if ( !in->Read(data, size) )
{
wxLogError("Read error");
}
else
{
// file data is in the buffer
...
}
delete [] data;
delete in;
}
http://docs.wxwidgets.org/stable/wx_wxftp.html#wxftp
You did not define what "downloading a file" means to you.
If you want to use HTTP to retrieve some content, you should use an HTTP client library like libcurl and issue the appropriate HTTP GET request.
I have written a program that uses qhttp to get a webpage. This works fine on Linux, but does not work on my Windows box (Vista). It appears that the qhttp done signal is never received.
The relevant code is:
Window::Window()
{
http = new QHttp(this);
connect(http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
url = new QUrl("http://something.com/status.xml");
http->setHost(url->host(), url->port() != -1 ? url->port() : 80);
if (!url->userName().isEmpty()) http->setUser(url->userName(), url->password());
}
void Window::retrievePage()
{
byteArray = new QByteArray;
result = new QBuffer(byteArray);
result->open(QIODevice::WriteOnly);
httpRequestAborted = false;
httpGetId = http->get(url->path(), result);
}
void Window::httpDone(bool error)
{
//Never gets here!
}
Any help would be appriecated.
Matt
This should not happen at all, i.e. QHttp works reliably both on Windows and Unix.
My advice is to check whether the serves gives proper response. This can be done e.g. by verifying that data transfer is fine. You can trace the status from QHttp's signal, e.g. dataReadProgress, requestStarted, requestFinished, and other related signals.
On the other hand, instead of using old QHttp, why not using the recommended QNetworkAccessManager instead? To get your feet wet quickly, check an example I posted to Qt Labs some time ago: image viewer with remote URL drag-and-drop support. It uses the said QNetworkAccessManager to grab the image from the dropped URL. Check the source-code, it is only 150 lines.
Rewritten as suggested by Ariya to use QNetworkAccessManager and looking at this example
This now works on Windows and Linux.
Window::Window()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(retrieveData(QNetworkReply*)));
}
void Window::retrieveMessage()
{
manager.get(QNetworkRequest(QUrl("http://...")));
}
void Window::retrieveData(QNetworkReply *reply)
{
QVariant statusCodeV =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
// "200 OK" received?
if (statusCodeV.toInt()==200)
{
QByteArray bytes = reply->readAll(); // bytes
}
reply->deleteLater();
}