How to do it...

Let's get started by observing the following steps:

  1. For this project, we need to install software called FileZilla Server, which we will use as the FTP server. FileZilla server can be downloaded from https://filezilla-project.org by clicking on the Download FileZilla Server button, as shown in the following screenshot:

  1. Once you have downloaded the installer, run it and install FileZilla Server by agreeing to all the default options, as shown in the following screenshot:

  1. When it has completed, open up FileZilla Server and press the Connect button, as shown in the following screenshot:

  1. After the server has been started, click on the user icon located at the top of the FileZilla Server control panel, as highlighted in the following screenshot:

  1. Once the Users window has been opened, click on the Add button located under the Users list to add a new user. Then, add a shared folder under the Shared folders list, where your users will be uploading and downloading files from, as shown in the following screenshot:

  1. We have now finished setting up FileZilla Server. Let's move on to Qt Creator and create a new Qt Widgets Application project. Then, open up mainwindow.ui and set up the GUI, as shown in the following diagram:

  1. Then, right-click on the Open button, Upload button, and Set Folder button and create their respective clicked() slot functions, as shown in the following code:
private slots:
void on_openButton_clicked();
void on_uploadButton_clicked();
void on_setFolderButton_clicked();
  1. After that, double-click on the list widget and select Go to slot.... Then, select the itemDoubleClicked(QListWidgetItem*) option and click OK, as shown in the following screenshot:

  1. Once you have created the slot function, open up mainwindow.h and add the following headers:
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QListWidgetItem>
#include <QMessageBox>
  1. Then, declare the getFileList() function, as follows:
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void getFileList();
  1. Then declare the following slot functions:
void downloadFileListFinished();
void uploadFileListFinished();
void uploadFileProgress(qint64 bytesSent, qint64 bytesTotal);
void uploadFileFinished();
void downloadFileProgress(qint64 byteReceived,qint64 bytesTotal);
void downloadFileFinished();
  1. Right after that, declare the following variables:
private:
Ui::MainWindow *ui;
QNetworkAccessManager* manager;
QString ftpAddress;
int ftpPort;
QString username;
QString password;
QNetworkReply* downloadFileListReply;
QNetworkReply* uploadFileListReply;
QNetworkReply* uploadFileReply;
QNetworkReply* downloadFileReply;
QStringList fileList;
QString uploadFileName;
QString downloadFileName;
  1. Then, open up mainwindow.cpp and add the following code to the class constructor:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
manager = new QNetworkAccessManager(this);
ftpAddress = "ftp://127.0.0.1/";
ftpPort = 21;
username = "myuser";
password = "123456";
getFileList();
}
  1. After that, implement the getFileList() function, as shown in the following code:
void MainWindow::getFileList() {
QUrl ftpPath;
ftpPath.setUrl(ftpAddress + "files.txt");
ftpPath.setUserName(username);
ftpPath.setPassword(password);
ftpPath.setPort(ftpPort);
QNetworkRequest request;
request.setUrl(ftpPath);
downloadFileListReply = manager->get(request);
connect(downloadFileListReply, SIGNAL(finished()), this, SLOT(downloadFileListFinished()));
}
  1. Then, define the on_openButton_clicked() slot function, which gets triggered when the Open button has been clicked, as shown in the following code:
void MainWindow::on_openButton_clicked() {
QString fileName = QFileDialog::getOpenFileName(this, "Select File", qApp->applicationDirPath());
ui->uploadFileInput->setText(fileName);
}
  1. Once you're done with that, implement the slot function that gets called when the Upload button has been clicked, as shown in the following example:
void MainWindow::on_uploadButton_clicked() {
QFile* file = new QFile(ui->uploadFileInput->text());
QFileInfo fileInfo(*file);
uploadFileName = fileInfo.fileName();

QUrl ftpPath;
ftpPath.setUrl(ftpAddress + uploadFileName);
ftpPath.setUserName(username);
ftpPath.setPassword(password);
ftpPath.setPort(ftpPort);

if (file->open(QIODevice::ReadOnly)) {
ui->uploadProgress->setEnabled(true);
ui->uploadProgress->setValue(0);

  1. Then, continue to implement the previous function, as shown in the following code:
    QNetworkRequest request;
request.setUrl(ftpPath);

uploadFileReply = manager->put(request, file);
connect(uploadFileReply, QNetworkReply::uploadProgress, this, &MainWindow::uploadFileProgress);
connect(uploadFileReply, QNetworkReply::finished, this, &MainWindow::uploadFileFinished);
} else {
QMessageBox::warning(this, "Invalid File", "Failed to open file for upload.");
}
}
  1. The following code shows what the on_setFolderButton_clicked() slot function looks like:
void MainWindow::on_setFolderButton_clicked() {
QString folder = QFileDialog::getExistingDirectory(this, tr("Open Directory"), qApp->applicationDirPath(), QFileDialog::ShowDirsOnly);
ui->downloadPath->setText(folder);
}
  1. Next, define the slot function which will be triggered when one of the list widget's items gets double-clicked, as shown in the following code:
void MainWindow::on_fileList_itemDoubleClicked(QListWidgetItem *item) {
downloadFileName = item->text();

QString folder = ui->downloadPath->text();
if (folder != "" && QDir(folder).exists()) {
QUrl ftpPath;
ftpPath.setUrl(ftpAddress + downloadFileName);
ftpPath.setUserName(username);
ftpPath.setPassword(password);
ftpPath.setPort(ftpPort);

  1. Then, continue to implement the previous function by using the following code:
    QNetworkRequest request;
request.setUrl(ftpPath);

downloadFileReply = manager->get(request);
connect(downloadFileReply, QNetworkReply::downloadProgress, this, MainWindow::downloadFileProgress);
connect(downloadFileReply, &QNetworkReply::finished, this, &MainWindow::downloadFileFinished);
} else {
QMessageBox::warning(this, "Invalid Path", "Please set the download path before download.");
}
}
  1. We're not quite done yet. Next, we will implement the downloadFileListFinished() function, which will be called automatically when the file list has been downloaded from the server, as shown in the following code:
void MainWindow::downloadFileListFinished() {
if(downloadFileListReply->error() != QNetworkReply::NoError)
QMessageBox::warning(this, "Failed", "Failed to load file list: " + downloadFileListReply->errorString());
else {
QByteArray responseData;
if (downloadFileListReply->isReadable())
responseData = downloadFileListReply->readAll();
ui->fileList->clear();
fileList = QString(responseData).split(",");
if (fileList.size() > 0) {
for (int i = 0; i < fileList.size(); i++) {
if (fileList.at(i) != "") {
ui->fileList->addItem(fileList.at(i));
}
}
}
}
}

  1. We also need to implement the function that will be called when we finish updating the file list to the server, as shown in the following example:
void MainWindow::uploadFileListFinished() {
if(uploadFileListReply->error() != QNetworkReply::NoError)
QMessageBox::warning(this, "Failed", "Failed to update file list: " + uploadFileListReply->errorString());
else
getFileList();
}
  1. The uploadFileProgress() function is used to display the progress bar when uploading a file to server, and it looks something like the following code:
void MainWindow::uploadFileProgress(qint64 bytesSent, qint64 bytesTotal) {
qint64 percentage = 100 * bytesSent / bytesTotal;
ui->uploadProgress->setValue((int) percentage);
}
  1. Next, we will define what happens after a file has been uploaded to the server. This function is slightly longer than the others, so we will split it into a few sections so that you don't get confused by it. First, we will loop through the file list and see if it already exists, as shown in the following example:
void MainWindow::uploadFileFinished() {
if(uploadFileReply->error() != QNetworkReply::NoError)
QMessageBox::warning(this, "Failed", "Failed to upload file: " + uploadFileReply->errorString());
else {
bool exists = false;
if (fileList.size() > 0) {
for (int i = 0; i < fileList.size(); i++) {
if (fileList.at(i) == uploadFileName)
exists = true;
}
}
if (!exists)
fileList.append(uploadFileName);

  1. Then, we will create a text file called files.txt and save the latest file list in it, as shown in the following code:
QString fileName = "files.txt";
QFile* file = new QFile(qApp->applicationDirPath() + "/" + fileName);
file->open(QIODevice::ReadWrite);
if (fileList.size() > 0) {
for (int j = 0; j < fileList.size(); j++) {
if (fileList.at(j) != "")
file->write(QString(fileList.at(j) + ",").toUtf8());
}
}
file->close();
  1. After that, open up files.txt and send it to the FTP server to update the file list, as shown in the following code:
QFile* newFile = new QFile(qApp->applicationDirPath() + "/" + fileName);
if (newFile->open(QIODevice::ReadOnly)) {
QUrl ftpPath;
ftpPath.setUrl(ftpAddress + fileName);
ftpPath.setUserName(username);
ftpPath.setPassword(password);
ftpPath.setPort(ftpPort);
  1. Then, continue to write the code that sends the file list to the FTP server, as shown in the following example:
            QNetworkRequest request;
request.setUrl(ftpPath);
uploadFileListReply = manager->put(request, newFile);
connect(uploadFileListReply, &QNetworkReply::finished, this, &MainWindow::uploadFileListFinished);
file->close();
}
QMessageBox::information(this, "Success", "File successfully uploaded.");
}
}

  1. We also need to define the function which updates the progress bar for downloading a file from the FTP server, as shown in the following code:
void MainWindow::downloadFileProgress(qint64 byteReceived,qint64 bytesTotal) {
qint64 percentage = 100 * byteReceived / bytesTotal;
ui->downloadProgress->setValue((int) percentage);
}
  1. Right after that, we can start implementing the downloadFileFinished() function, which gets called when a file has been downloaded from the server. First, we need to check whether the file has successfully downloaded, as shown in the following example:
void MainWindow::downloadFileFinished() {
if(downloadFileReply->error() != QNetworkReply::NoError)
QMessageBox::warning(this, "Failed", "Failed to download file: " + downloadFileReply->errorString());
else {
QByteArray responseData;
if (downloadFileReply->isReadable())
responseData = downloadFileReply->readAll();
  1. If it has, we'll save the file into the download directory which the user has set, as shown in the following code:
        if (!responseData.isEmpty()) {
QString folder = ui->downloadPath->text();
QFile file(folder + "/" + downloadFileName);
file.open(QIODevice::WriteOnly);
file.write((responseData));
file.close();
QMessageBox::information(this, "Success", "File successfully downloaded.");
}
}
}
  1. Before we start testing the program, let's create an empty text file called files.txt and place it in the folder which you have linked to the FTP user you set in FileZilla Server.
  1. Lastly, build and run the program. Try and upload some files to the FTP server. If it works, the file list should be updated and be displayed on the List Widget. Then, try and double-click on the filename on the list widget and download the file to your computer, as shown in the following screenshot:

  1. Congratulations, you have now successfully created a working FTP program!