我在ip是10.0.2.10,用户是qxy这台虚拟机里安装了vsftpd,并且添加了用户test,用户目录在/home/test下,进行如下操作,出现这样的问题: 在QT运行ftp.pro项目,主要代码如下: ftpmanager.cpp如下:
#include "ftpmanager.h"
#include <QDebug>//qDebug类似于print()函数,用于在控制台输出信息
class FtpManager;
FtpManager::FtpManager(QString _host, QString userName, QString passWd, qint16 _port, QObject *parent):
QObject(parent),// *parent: 指向QObject的指针,FtpManager的父对象,调用QObject的构造函数,设置父对象
m_userName(userName),// 存储传入的用户名
m_passwd(passWd),
m_File(0),// 初始化文件指针,设置为nullptr
m_IsOpenFile(false)// 初始化文件打开状态,设置为false
{
//构建Qftp对象,对象为this
myFtp = new QFtp(this);
//连接到ftp服务器
myFtp->connectToHost(_host,_port);
//进度条显示(连接数据传输进度信号到槽函数S_upDateProgress,用于更新进度条)
connect(myFtp,SIGNAL(dataTransferProgress(qint64,qint64)),
SLOT(S_upDateProgress(qint64,qint64)));
//状态显示(连接命令完成信号到槽函数S_commandFinish,用于处理命令执行结果)
connect(myFtp,SIGNAL(commandFinished(int,bool)),
SLOT(S_commandFinish(int,bool)));
//文件列表(连接服务器文件列表信息信号到槽函数S_listInfo,用于获取文件列表)
connect(myFtp,SIGNAL(listInfo(QUrlInfo)),SLOT(S_listInfo(QUrlInfo)));
}
FtpManager::~FtpManager()//FtpManager类的析构函数,释放之前创建的QFtp对象
{
delete myFtp;
}
//停止Ftp动作
void FtpManager::S_abort()
{
myFtp->abort();
}
void FtpManager::S_list()
{
myFtp->list();
}
// 槽函数,用于获取并打印文件的详细信息。参数_urInfo: QUrlInfo对象,包含文件的信息
void FtpManager::S_listInfo(QUrlInfo _urInfo)
{// 打印文件的名称、大小和所有者信息。/*.toLatin1()*/是用来将文件名转化为ASCII编码的。
qDebug() <<_urInfo.name()/*.toLatin1()*/<<" "<<_urInfo.size()<<" " <<_urInfo.owner();
}
//下载文件(当isRese==true为续传下载)
void FtpManager::S_dloadFile(QString _remoteFile,QString _localFile,bool isRese)
{
m_File = new QFile(_localFile);//m_File用于存储本地文件对象,m_IsOpenFile用于跟踪文件是否成功打开
if(!isRese)
{
qDebug() << tr("文件%1的普通下载... ...").arg(_remoteFile);//%1是格式占位符,允许插入变量或者值到字符串中
/*当使用 tr() 函数(或者 QString::arg() 方法)来处理这个字符串时,%1 会被后面传递的参数所替换。
* tr() 函数是 Qt 提供的国际化函数,用于翻译字符串。如果你没有使用国际化,tr() 函数的行为类似于 QString::arg()。*/
if(m_File->open(QIODevice::WriteOnly))//以只写方式打开文件
{
m_IsOpenFile = true;//如果打开成功
myFtp->get(_remoteFile,m_File);//通过myFtp对象的get方法开始下载文件
}
else//如果文件打开失败,函数会输出错误信息并清理资源
{
delete m_File;
m_File = NULL;
qDebug() << tr("本地文件%1打开失败!").arg(_localFile);
}
}
else
{
qDebug() << tr("文件%1的续传下载... ...").arg(_remoteFile);
if(m_File->open(QIODevice::Append))
/*如果文件以追加模式成功打开,文件指针默认在文件末尾,
追加模式:当你向文件写入数据时,数据会被追加到文件的末尾,而不是覆盖现有数据。*/
{
m_IsOpenFile = true;
myFtp->rawCommand(tr("REST %1").arg(m_File->size()));//.arg(m_File->size())将%1替换为当前文件的大小。tr是用来翻译字符串的。REST命令用于断点续传
myFtp->m_isConLoad = true; //设置当前现在为续传
myFtp->get(_remoteFile,m_File);
}
else//如果文件打开失败,函数会输出错误信息并清理资源
{
delete m_File;
m_File = NULL;
qDebug() << tr("本地文件%1打开失败").arg(_localFile);//qDebug类似于print()函数,用于在控制台输出信息
}
}
}
//上传文件(当isRese==true为续传上传)
void FtpManager::S_uloadFile(QString _localFile,QString _remoteFile,bool isRese)
{
m_File = new QFile(_localFile);
if(m_File->open(QIODevice::ReadOnly))
{
m_IsOpenFile = true;
if(!isRese)
{
qDebug() << tr("文件%1的普通上传... ...").arg(_localFile);
myFtp->put(m_File,_remoteFile); //上传
}
else
{
qDebug() << tr("文件%1的续传... ...").arg(_localFile);
//在QFtp中定义续传方法
myFtp->conPut(m_File,_remoteFile); //续传
}
}
else
{
delete m_File;
m_File = NULL;
qDebug() << tr("本地文件%1打开失败!").arg(_localFile);
}
}
//更新进度条
void FtpManager::S_upDateProgress(qint64 _used, qint64 _total)//qin64是QT特有的数据类型,范围-2的63到2的63-1,存储非常大的整数值
{
int tmpVal = _used / (double)_total * 100;//已传输文件大小/总大小
emit G_getProgressVal(tmpVal);//emit关键字,用于发出信号
}
//ftp服务提示信息
void FtpManager::S_commandFinish(int tmp, bool en)//声明了一个名为 S_commandFinish 的槽函数,它属于 FtpManager 类
{
Q_UNUSED(tmp);//tmp变量在当前代码未使用,为避免产生警告,使用宏Q_UNUSED声明一下
if(myFtp->currentCommand() == QFtp::ConnectToHost){
if(en)
qDebug() << (tr("连接服务器出现错误:%1").arg(myFtp->errorString()));
else
{
qDebug() << (tr("连接到服务器成功"));
myFtp->login(m_userName,m_passwd); //登陆服务器
}
}
if (myFtp->currentCommand() == QFtp::Login){
if(en)
qDebug() << (tr("登录出现错误:%1").arg(myFtp->errorString()));
else
qDebug() << (tr("登录服务器成功"));
}
if (myFtp->currentCommand() == QFtp::Get)//下载
{
if(en)
{
qDebug() << (tr("下载出现错误:%1").arg(myFtp->errorString()));
}
else
{
qDebug() << (tr("已经完成下载"));
m_File->flush();
}
m_File->close();
m_IsOpenFile = false;
delete m_File;
m_File = NULL;
}
else if(myFtp->currentCommand() == QFtp::Put)//上传
{
if(en)
{
qDebug() << (tr("上传出现错误:%1").arg(myFtp->errorString()));
}
else
{
qDebug() << (tr("已经完成文件上传"));
}
m_File->close();
m_IsOpenFile = false;
delete m_File;
m_File = NULL;
}
else if (myFtp->currentCommand() == QFtp::Close)
{
qDebug() << (tr("已经关闭连接"));
if(m_IsOpenFile)
{
m_File->close();
delete m_File;
m_File = NULL;
}
}
}
mainwindow.cpp如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
manager = new FtpManager("10.0.2.10","test","qaz&&123",21,this);
manager2 = new FtpManager("10.0.2.10","test","qaz&&123",21,this);
//manager = new FtpManager("192.168.136.144","zhj","123456",21,this);//zhj是FTP 服务器上的用户名
// manager2 = new FtpManager("192.168.136.144","zhj","123456",21,this);
connect(manager,SIGNAL(G_getProgressVal(int)),SLOT(S_updateProgess(int)));
connect(manager2,SIGNAL(G_getProgressVal(int)),SLOT(S_updateProgess2(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
//更新进度条
void MainWindow::S_updateProgess(int _val)
{
ui->progressBar->setValue(_val);
}
//更新进度条
void MainWindow::S_updateProgess2(int _val)
{
ui->progressBar_2->setValue(_val);
}
//普通下载,客户端从服务器那里下载
void MainWindow::on_downloadBn_clicked()
{
manager->S_dloadFile("file.txt","/home/test");//要下载的文件名称和要被保存的路径。
}
//普通上传,客户端向服务器上传文件
void MainWindow::on_uploadBn_clicked()
{
manager->S_uloadFile(QString("/home/qxy"),"ftp.java");//指示manager对象尝试将本地路径G:/学习中的名为“续传”的文件上传到FTP服务器
//manager->S_uloadFile(QString("G:/学习"),"续传");
}
//下载(续传)
void MainWindow::on_downloadBn_2_clicked()
{
manager2->S_dloadFile("file.txt","/home/test",true);
//该事件指示manager2对象尝试从FTP服务器下载一个名为“续传”的文件,
// 并将其保存到本地路径G:/QTWorkspace.zip。true参数表明启用断点续传功能,如果之前的下载被中断,
// 它将从中断的地方继续下载,而不是从头开始。
}
//停止
void MainWindow::on_abort_clicked()
{
manager2->S_abort();
}
//上传(续传)
void MainWindow::on_abort_2_clicked()
{
manager2->S_uloadFile("/home/test/file.txt","file.txt",true);
// manager2->S_uloadFile("D:/QFtp续传.rar","QFtp续传.rar",true);
}
//停止
void MainWindow::on_abort_3_clicked()
{
manager->S_abort();
}
//显示文件列表
void MainWindow::on_downloadBn_3_clicked()
{
manager->S_list();
}
我主要是在mainwindow.cpp这里修改文件路径。
main.cpp如下:
#include "mainwindow.h" // 引入主窗口的头文件,用于创建应用程序的主窗口
#include <QApplication> // 引入QApplication类,用于创建和管理Qt应用程序,QApplication是Qt应用程序的主控制类,负责管理应用程序的控制流和主要设置。
#include <QTextCodec> // 引入QTextCodec类,用于处理文本编码和解码
// 程序的主函数,程序执行的入口点,它接收两个参数:argc(命令行参数的数量)和argv(命令行参数的字符串数组)。
int main(int argc, char *argv[])
{
// 以下两行代码被注释,用于设置应用程序的区域设置为UTF-8编码
// 如果需要处理非ASCII字符,应取消注释
// QTextCodec *codec = QTextCodec::codecForName("UTF-8");
// QTextCodec::setCodecForLocale(codec);
QApplication a(argc, argv); // 创建QApplication对象,传入命令行参数argc和argv,创建一个QApplication对象实例。这个对象负责管理应用程序的生命周期和资源。
MainWindow w; // 创建MainWindow对象,它是应用程序的主窗口
w.show();// 调用show方法,显示主窗口
return a.exec();// 启动应用程序的事件循环,等待用户操作直到退出。exec()方法返回时,应用程序即将关闭,并返回退出码
}
运行结果如下:
本地文件打开失败,/home/qxy是服务器路径,/home/test是客户端用户路径。