基于QFtp的ftp客户端

1、问:Qt5怎么利用QFtp类实现ftp?
答:因为Qt5以上版本将QFtp类移除的缘故,需要自己下载qtftp源码并编译生成dll和lib文件,这个过程是痛苦的,痛苦的结果就是你会除了使用qt creator编译之外,掌握使用qmake编译qt程序的方法。当然这个过程还是需要自己亲身体会哦。
2、问:服务器跟本地编码不用,界面出现乱码?
答:这么直接的问题…当然得需要我来好好的研究一下咯,因为我也因为这个问题搞迷糊了很久的。最简单的方式就是::自己写一个编码转换的函数咯。
吐槽一下:Qt对中文的处理真是醉了,醉了。。。

/********************************************************
 * creator      : @ji
 * function     : 将ftp编码格式转换为本地编码格式
 * Date         : 2016-10-21
 * parameter    : 
 * ******************************************************/
QString ftpCodeToLocalCode( const QString &ftpString )
{
    #ifdef Q_OS_WIN
        return  QString::fromLocal8Bit(ftpString.toLatin1());
    #else
        QTextCodec *codec = QTextCodec::codecForName("utf8");
        if (codec) { return codec->toUnicode(ftpString.toLatin1()); }
        else { return QString(""); }
    #endif
}

看,下面的编码转换函数还是挺简单的吧,是的嘞!当然解决界面本地编码的方式还是有更简单的哦!
只需要在main.cpp文件里面添加下面这三行代码就可以啦!当然不要忘记引入头文件哦!

#include <QTextCodec>
QTextCodec::setCodecForTr( QTextCodec::codecForLocale() );
QTextCodec::setCodecForLocale( QTextCodec::codecForLocale() );
QTextCodec::setCodecForCStrings( QTextCodec::codecForName("UTF-8") );

3、服务器列表界面介绍
先来看看图吧
这里写图片描述
是不是很酷炫,当然在这儿大多初学者肯定会觉得用QListWidget就可以了,是的,QListWidget是能够实现item的,但是我没有找到QListWidget中item到底怎样才能选中多个item。
(a)问:那么你是怎样实现同时选中多个?
答:其实也是很简单的嘛,我小小的修改了一下QListWidget类,自己重新写了一个QListWidgetNt类就实现了,这里的item并不是QListWidgetItem类,问了方便,也就小小的修改了一下QListWidgetItem类,就变成现在这个样子了。
(b)问:点击item服务器会不会切换?
答:当然会切换了,要不然前面不都说了一堆废话吗,这里点击服务器列表对应的item,会实现服务器的切换,根据点击的IP切换至相应的服务器。

4、加载本地资源管理器
本地文件资源管理器包括两部分,最顶层的盘符(也就是常说的C/D/E/F盘)和各个盘符下面的文件和文件夹 ,在这里会有好几种选择;使用QFilesystemModel类加载;使用QFileInfoList加载;等等。。。其实我觉得各有千秋吧,关键是要看你会用QTreeWidget控件还是QTreeView控件来显示文件。我使用的QListWidget。
(a)问:怎样获取文件列表信息?
答:下面这几行代码会将盘符和某一个文件夹下面的信息全部append进QFileInfoList中,其中的dir是文件夹路径

QDir dir;
if ( m_ui.le_Local->text().isEmpty() ) { dir.setPath( "//" ); }
else { dir.setPath( m_ui.le_Local->text() ); }
dir.cd ( str + "/" );
QFileInfoList list = QDir::drives();
QFileInfoList m_List << dir.entryInfoList (string, QDir::AllEntries|QDir::NoDotAndDotDot, QDir::DirsFirst);

获取到文件列表之后就要将文件信息显示在界面上,毕竟我们这里是可视化嘛!
(b)问:怎样显示文件信息?
答:看我的。其实就是new一个item添加进去就好了。

for(unsigned int i = 0; i < list.count(); i++)
{
    QFileInfo temFileInfo( list.at(i) );
    QString filename = temFileInfo.fileName();
    QTreeWidgetItem *item = new QTreeWidgetItem;
        QPixmap pixmap(temFileInfo.isDir() ? ":/WinScp/Images/dir.png" : ":/WinScp/Images/file.png");
        //设置名称
        item->setText( 0, temFileInfo.fileName() );
        //设置最后修改时间
        item->setText( 1, temFileInfo.lastModified().toString("yyyy/MM/dd/hh:mm") );
        //设置大小
        item->setText( 3, QString::number( temFileInfo.size() ) + "kb" );
        if ( filename.isEmpty() ) { item->setText( 0, list.at(i).absoluteDir().absolutePath().mid( 0, 2 ) ); }
        if( temFileInfo.isDir () ) 
        {
        //设置类型
            item->setText( 2, QObject::tr("Dir") );
            item->setText( 3, QObject::tr(" ") );
        }
        else if(temFileInfo.isFile () ) { item->setText( 2, QString("file") ); }
        //根据是文件夹还是文件设置相应的图标
        item->setIcon(0, pixmap);
        m_Tw->addTopLevelItem(item);
}

5、双击文件夹显示该文件夹下面的文件信息
这种方式其实和第一初始化的时候差不多,也就是上面所说的怎样获取文件列表信息。
6、问:现在进入一个文件夹后,怎么返回上一级呢?
答:其实每个文件夹下面都有两个隐藏的文件夹,名称分别为”.”和”..”,相信玩过Linux的人都知道的,点击”..”文件夹会返回上一级,当然这里为了方便,每次在进入一个文件夹后都会把它的路径更新在一个QLineEdit中,模式跟Windows下的资源管理器是一样的。下面以获取FTP服务器的上一级目录为例。本地文件的雷同。

QString serverCurPath = m_ui.le_Ftp->text();
    serverCurPath = serverCurPath.left(serverCurPath.lastIndexOf('/'));
    serverCurPath = serverCurPath.left(serverCurPath.lastIndexOf('/'));
    if ( serverCurPath.isEmpty() )
    {
        m_pFileTrans->cd("/");
        m_ui.le_Ftp->setText("/");
    } 
    else
    {
        m_pFileTrans->cd( LocalCodeToFtpCode( serverCurPath ));
        m_ui.le_Ftp->setText( serverCurPath + "/" );
    }
    m_pFileTrans->list();

7、问:怎么获取文件下载和上传的进度?
答:我能告诉你这些其实Qt都已经给你做好了吗?当然为了所谓的界面美化你自己也可以重新写一个咯,这个我是不会拒绝的啦!Qt中QProgressDialog类已经将一切都封装好了,要用的时候直接设置它的值就好了。

connect(m_pFileTrans, SIGNAL( dataTransferProgress(qint64,qint64) ), this, SLOT( slot_UpdateDataTransferProgress(qint64,qint64) ));
void WinScp::slot_UpdateDataTransferProgress( qint64 m_Read, qint64 m_All)
{
    m_pProgressDlg->setMaximum( m_All );
    m_pProgressDlg->setValue( m_Read );
}

8、问:说了一大堆,上传和下载是怎么实现的?
答:都告诉你了是用QFtp实现的。方法当然是利用QFtp类提供的put函数啦,就是获取该文件在本地的路径,和FtpSer上的路径,接着调用put函数就行啦!啥,我的不是put函数,~^_^~我是重新封装的QFtp类啊,大哥。

QFileInfo file( m_ui.le_Local->text() + m_strLocalUpFileName );
QString serverFileName = m_ui.le_Ftp->text() + strName;
QString clientFileName = m_ui.le_Local->text()+ strName;
m_pFileTrans->UploadFile(clientFileName, serverFileName);

当然,下载也就不需要多说啥了,基本和上传是一样的啦!啥,还不会,那就只能去看QFtp的官方文档了,哥只能帮你到这儿了。
9、问:QFtp是怎么连接和登录的?
答:当然是网络咯,有网络就必须要有TCP啦,还是你熟悉的三次握手的味道。。

if ( m_pFileTrans )
 {
        m_pFileTrans->abort();
        m_pFileTrans->deleteLater();
        m_pFileTrans = 0;
        m_ui.Tw_Ftp_List->clear();
        m_ui.le_Ftp->clear();
    }
    if (!networkSession || !networkSession->isOpen())
    {
        if ( manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
         {
            if (!networkSession)
            {
                QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
                settings.beginGroup(QLatin1String("QtNetwork"));
                const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
                settings.endGroup();
                QNetworkConfiguration config = manager.configurationFromIdentifier(id);
                if ((config.state() & QNetworkConfiguration::Discovered) != QNetworkConfiguration::Discovered) 
                {
                        config = manager.defaultConfiguration();
                }
                networkSession = new QNetworkSession(config, this);
                connect(networkSession, SIGNAL(opened()), this, SLOT(SlotConnectToFtp()));
                connect(networkSession, SIGNAL(error(QNetworkSession::SessionError)), this, SLOT(SlotEnableConnectButton()));
            }
            networkSession->open();
            return;
        }
    }
    //为了方便转还服务器跟本地的编码问题,这里重新实现了QFtp类,当然也没有多大的改变,只是增加了编码转换的两个函数
    m_pFileTrans = new FileTrans;
    connect( m_pFileTrans, SIGNAL( commandFinished(int,bool) ), this, SLOT( slot_FtpCommandFinished(int,bool) ));
    connect(m_pFileTrans, SIGNAL( listInfo(QUrlInfo) ), this, SLOT( slot_AddFtpToList( QUrlInfo) ) );
    connect(m_pFileTrans, SIGNAL( dataTransferProgress(qint64,qint64) ), this, SLOT( slot_UpdateDataTransferProgress(qint64,qint64) ));
    m_pFileTrans->connectToHost( m_pUrl, 21 );
    if ( !m_pUserName.isEmpty() & !m_pPsw.isEmpty() )
    { 
        m_pFileTrans->login( m_pUserName, m_pPsw );
        slot_AddIpToTB( m_pUrl, m_pUserName, m_pPsw );
    }
    else { m_pFileTrans->login(); }

10、接下来看看FtpSer的返回数据吧:
当然这只是一个逻辑,具体实现就要考各位大侠啦!

if ( m_pFileTrans->currentCommand() == QFtp::ConnectToHost )
{
    if ( error ) {//错误处理 }
    /*
    *正常代码处理
    */
    return;
    }
    if ( m_pFileTrans->currentCommand() == QFtp::Login )
    {
        if ( error ) {//错误处理 }
        /*
         *正常代码处理
         */
        return;
    }
    if ( m_pFileTrans->currentCommand() == QFtp::Get ) 
    {
        if ( error ) {//错误处理 }
        else  { /**正常代码处理*/ }
        delete  m_pFileTrans->m_pFile;
        return;
    }
    if ( m_pFileTrans->currentCommand() == QFtp::Put )
    {
        if ( error ) {//错误处理 }
        else  { /**正常代码处理*/ }
        delete  m_pFileTrans->m_pFile;
        return;
    }

至此,一个简单的基于QFtp的ftp客户端就能实现,上面这些只是我在做的过程中遇到的一些问题,希望可以帮到和我一样初学者吧。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值