文章目录
- 0 背景
- 1 搭建文件服务器
- 2 代码实现文件上传和下载
- 2.1 在pro文件中添加网络支持
- 2.2 创建网络管理类
- 2.3 文件上传
- 2.4 文件下载
- 3 扩展(其他方法实现文件上传和下载)
- 3.1 python
- 3.2 npm
- 3.3 ftp服务器
- 4 完整的代码
0 背景
因为需要使程序具备在远程软件在服务器的上传和下载文件的功能,所以研究了一下怎么实现。
1 搭建文件服务器
常用的文件服务器有apache、npm、ftp,这里选择的apache2,因为搭建和使用都比较方便。
1,安装
sudo apt update
sudo apt install apache2
2,创建身份验证用户::
# 新增用户
htpasswd -c /etc/apache2/webdav.password 【webdav用户名】
# 更改密码
htpasswd -b /etc/apache2/webdav.password 【这里换成你要登录webdav的名字】
# 删除用户
htpasswd -D htpasswd.user Jack
3,编写配置文件
vim /etc/apache2/sites-available/000-default.conf
修改为如下内容:
<VirtualHost *:9022>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory "/var/www/html">
Dav on
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Require all granted
allow from all
</Directory>
DavLockDB "/home/apache2/data/DavLock"
# 配置一个虚拟目录
Alias /webdav /home/apache2/data
<Directory /home/apache2/data>
#开启Dav支持
Dav On
# 禁止浏览器显示目录,将-Indexes前的减号去掉为允许显示(当index.html不存在时)
Options Indexes
# 认证方式,虽然这种方式不安全但可以快速架设成功我们需要的服务
AuthType Basic
# 这里的名字随意写
AuthName "WebDAV"
# 非常关键的用户管理文件
AuthUserFile /etc/apache2/webdav.password
AuthBasicProvider file
# 允许userfile.pass里的所有用户访问
Require valid-user
AllowOverride All
</Directory>
</VirtualHost>
授予文件访问权限:
sudo chmod 775 /var/www
4,启动并使其自动运行:
sudo systemctl start apache2
sudo systemctl status apache2
sudo systemctl enable apache2
5,其他指令
# 重启 Apache(完全停止并重新启动 Apache 服务。这适用于那些进行了重大更改并需要完全重启服务的情况):
sudo systemctl restart apache2
# systemctl reload 只是重新加载 Apache 的配置文件,而不会中断服务的运行:
sudo systemctl reload apache2
2 代码实现文件上传和下载
2.1 在pro文件中添加网络支持
QT += network
2.2 创建网络管理类
# .h文件中添加:
private:
//发送网络请求和接受应答
QNetworkAccessManager* m_networkAccessManager;
# .cpp文件中添加:
m_networkAccessManager = new QNetworkAccessManager();
2.3 文件上传
1,功能函数;
//上传文件
void MainInterface::uploadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath)
{
// QFile file(sourceFilePath);
m_readFile.setFileName(sourceFilePath);
if (m_readFile.open(QIODevice::ReadOnly)){
QFileInfo fileInfo(sourceFilePath);
QString fileName = fileInfo.fileName();
//如果目的文件名,使用原文件名
if(purposeFilePath == ""){
purposeFilePath = fileName;
}
QString urlText = QString("http://192.168.0.211:9022/webdav/") + purposeFilePath;
qDebug()<<urlText;
QUrl url(urlText);
// 设置用户名和密码凭据
QString username = "uploaduser2";
QString password = "test";
url.setUserName(username);
url.setPassword(password);
m_httpRequest.setUrl(url);
m_networkAccessManager->put(m_httpRequest, &m_readFile);
}else{
qDebug()<<"打开文件失败";
}
}
2,方法调用;
//文件上传
QString sourceFilePath = QString("E:/s1.xlsx");
QString purposeFilePath = "";
uploadFileFromHttpServerApacheWebdav(sourceFilePath, purposeFilePath);
2.4 文件下载
这里下载使用的是post方法,而没有使用get。
1,功能函数;
//从服务器上下载文件
void MainInterface::downloadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath){
QString urlText = QString("http://192.168.0.211:9022/webdav/") + sourceFilePath;
QUrl url(urlText);
// 设置用户名和密码凭据
QString username = "uploaduser2";
QString password = "test";
url.setUserName(username);
url.setPassword(password);
m_httpRequest.setUrl(url);
QString saveFilePath = QCoreApplication::applicationDirPath() + QString("/") ;//末尾无斜杠
m_purposeSaveFilePath = saveFilePath + purposeFilePath;
m_isReceiveFile = true;
m_networkAccessManager->get(m_httpRequest);
}
//处理所有post请求
connect(m_networkAccessManager, &QNetworkAccessManager::finished,
this, [&](QNetworkReply *reply){
if (reply->error()) {
qDebug() << "Download error:" << reply->errorString();
} else {
//接收并下载文件
if(m_isReceiveFile == true){
m_isReceiveFile = false;
// 处理获取到的文件内容
QByteArray fileData = reply->readAll();
qDebug() << "写入下载的数据:"<<m_purposeSaveFilePath;
QFile file(m_purposeSaveFilePath);
//QFile file(purposeFilePath);
if (file.open(QIODevice::WriteOnly)) {
file.write(fileData);
file.close();
}
}else{
QVariant data = reply->readAll();
qDebug()<<data.toString();
}
}
reply->deleteLater();
});
2,方法调用;
QString sourceFilePath = "s5.xlsx";
QString purposeFilePath = "data/s5.xlsx";
downloadFileFromHttpServerApacheWebdav(sourceFilePath, purposeFilePath);
3 扩展(其他方法实现文件上传和下载)
3.1 python
下载和安装python3,然后使用如下指令开启服务器
python -m http.server -b 127.0.0.1
3.2 npm
1,安装
执行代码:
npm install http-server -g
-g 参数代表全局安装一定不要省略,全局安装后,全局都可以使用
2,在需要共享的文件夹下,运行
http-server
3.3 ftp服务器
1,安装(https://www.myfreax.com/how-to-setup-ftp-server-with-vsftpd-on-debian-11/)
sudo apt update
sudo apt install vsftpd
sudo systemctl status vsftpd
2,新建ftp登录账户
# 创建一个帐户
sudo adduser ftpuser
# 为了让用户能够访问FTP服务器,你需要将其添加到FTP用户组中。输入以下命令:
sudo usermod -a -G ftp ftpuser
3,修改配置文件
修改/etc/shells
sudo vim /etc/shells
#写入以下这行,否则ftpuser无法登录
/usr/sbin/nologin
修改内容:
# 启用上传
write_enable=YES
#限制ftp用户只能待在自己的家目录,不能跳到其他目录
chroot_local_user=YES
allow_writeable_chroot=YES #不加入这条会导致ftp用户对家目录没有写入权限
chroot_local_user=YES #限制ftp用户只能待在自己的家目录,不能跳到其他目录
userlist_enable=YES #使用userlist限制可以登录ftp的账户
userlist_deny=NO #这里是NO则userlist是白名单,YES就是黑名单
4,重启vsftpd服务
sudo systemctl restart vsftpd
systemctl start vsftpd.service
sudo systemctl status vsftpd
4 完整的代码
MainInterface.h
#ifndef MAIN_INTERFACE_H
#define MAIN_INTERFACE_H
#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QFile>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainInterface;
}
QT_END_NAMESPACE
class MainInterface : public QMainWindow
{
Q_OBJECT
public:
MainInterface(QWidget *parent = nullptr);
~MainInterface();
private:
Ui::MainInterface *ui;
private:
//发送网络请求和接受应答
QNetworkAccessManager* m_networkAccessManager;
//是否是接收文件
bool m_isReceiveFile = false;
//目的存储路径
QString m_purposeSaveFilePath;
//请求
QNetworkRequest m_httpRequest;
//文件下载
QFile m_readFile;
/**
* @brief downloadFileFromHttpServerApacheWebdav:从apache2服务器上下载文件(get)
* @param sourceFilePath:源文件路径(最前面不带/,)
* @param purposeFilePath:目的文件路径(最前面不带/,最前面包含了运行文件的路径)
*/
void downloadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath);
/**
* @brief 上传文件到服务器上(put)
* @param sourceFilePath
* @param purposeFilePath
*/
void uploadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath);
};
#endif // MAIN_INTERFACE_H
MainInterface.cpp
#include "main_interface.h"
#include "ui_main_interface.h"
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QObject>
#include <QFile>
#include <QFileInfo>
MainInterface::MainInterface(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainInterface)
{
ui->setupUi(this);
// qDebug() << QSslSocket::supportsSsl()//是否支持,不支持就说明没有openSSL
// << QSslSocket::sslLibraryBuildVersionString()//运行时需要的版本
// << QSslSocket::sslLibraryVersionString();//可用的版本
m_networkAccessManager = new QNetworkAccessManager();
//处理所有post请求
connect(m_networkAccessManager, &QNetworkAccessManager::finished,
this, [&](QNetworkReply *reply){
if (reply->error()) {
qDebug() << "Download error:" << reply->errorString();
} else {
//接收并下载文件
if(m_isReceiveFile == true){
m_isReceiveFile = false;
// 处理获取到的文件内容
QByteArray fileData = reply->readAll();
qDebug() << "写入下载的数据:"<<m_purposeSaveFilePath;
QFile file(m_purposeSaveFilePath);
//QFile file(purposeFilePath);
if (file.open(QIODevice::WriteOnly)) {
file.write(fileData);
file.close();
}
}else{
QVariant data = reply->readAll();
qDebug()<<data.toString();
}
}
reply->deleteLater();
});
//文件下载
// QString sourceFilePath = "s5_ExamineExamOne_1721294100.xlsx";
// QString purposeFilePath = "data/s5_ExamineExamOne_1721294100.xlsx";
// downloadFileFromHttpServerApacheWebdav(sourceFilePath, purposeFilePath);
//文件上传
QString sourceFilePath = QString("E:/s1.xlsx");
QString purposeFilePath = "";
uploadFileFromHttpServerApacheWebdav(sourceFilePath, purposeFilePath);
}
MainInterface::~MainInterface()
{
delete ui;
}
//从服务器上下载文件
void MainInterface::downloadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath){
QString urlText = QString("http://192.168.0.211:9022/webdav/") + sourceFilePath;
QUrl url(urlText);
// 设置用户名和密码凭据
QString username = "uploaduser2";
QString password = "test";
url.setUserName(username);
url.setPassword(password);
m_httpRequest.setUrl(url);
QString saveFilePath = QCoreApplication::applicationDirPath() + QString("/") ;//末尾无斜杠
m_purposeSaveFilePath = saveFilePath + purposeFilePath;
m_isReceiveFile = true;
m_networkAccessManager->get(m_httpRequest);
}
//上传文件
void MainInterface::uploadFileFromHttpServerApacheWebdav(QString sourceFilePath, QString purposeFilePath)
{
// QFile file(sourceFilePath);
m_readFile.setFileName(sourceFilePath);
if (m_readFile.open(QIODevice::ReadOnly)){
QFileInfo fileInfo(sourceFilePath);
QString fileName = fileInfo.fileName();
//如果目的文件名,使用原文件名
if(purposeFilePath == ""){
purposeFilePath = fileName;
}
QString urlText = QString("http://192.168.0.211:9022/webdav/") + purposeFilePath;
qDebug()<<urlText;
QUrl url(urlText);
// 设置用户名和密码凭据
QString username = "uploaduser2";
QString password = "test";
url.setUserName(username);
url.setPassword(password);
m_httpRequest.setUrl(url);
m_networkAccessManager->put(m_httpRequest, &m_readFile);
}else{
qDebug()<<"打开文件失败";
}
}