基于QT实现文件上传和下载功能

本文实例为大家分享了基于QT实现文件上传和下载的具体代码,供大家参考,具体内容如下

功能

  • 支持文件上传功能
  • 支持文件下载功能
  • 支持断点续传功能
  • 支持连续多个文件的上传下载

文件上传下载流程

在确认断点的时候会利用md5进行数据校验,防止数据发生更改。

服务端

  • 采用多线程的Reactor模式。即一个线程对应多个filesocket进行文件上传下载。线程个数可设置,默认为1.
  • FileServer 继承QTcpServer,实现incomingConnection虚函数。当有新的连接到来时,会创建FileSocket并采用moveToThread接口,将其移入到当前活跃socket数量最少的线程中。
  • FileSocket采用Qt本身的事件循环和信号槽机制进行数据传输。通过设置两者的交互机制,避免了tcp的粘包问题以及QTcpSocket的readyRead信号触发问题。

服务端代码:

//fileserver.h
#ifndef FILESERVER_H
#define FILESERVER_H

#include <QObject>
#include <QTcpServer>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QMap>
#include <QString>
#include <QThread>

class FileServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit FileServer(QString param_server_name,quint8 param_thread_count=1,QObject *parent = nullptr);
    ~FileServer();

    QString getServername() {return m_server_name;}
    quint8 getThreadCount() {return m_thread_count;}
    //获取当前每个线程的活跃socket数量
    void threadMonitor(QMap<qint32,quint32>& param_info);

signals:

public slots:
    //开始监听
    bool run(quint16 port);
    void socketClose(qint32 id);

protected:
    void incomingConnection(qintptr socketDescriptor);

    struct ThreadInfo //线程信息,包括标志线程的ID和活跃socket的数量
    {
        qint32 id;
        QThread msg_thread;
        quint32 active_count;
    };
    //获取活跃socket数量最小的线程id
    qint32 getMinActiveThread();

private:
    QString m_server_name;
    quint8 m_thread_count;
    ThreadInfo* m_socket_thread;

};

//fileserver.cpp
#include "fileserver.h"
#include "filesocket.h"

#include <QTcpSocket>
#include <QHostAddress>

FileServer::FileServer(QString param_server_name,quint8 param_thread_count,QObject *parent) :
    QTcpServer(parent),
    m_server_name(param_server_name),
    m_thread_count(param_thread_count)
{
    //根据用户给定的线程个数进行线程信息数组的申请,并进行初始化
    this->m_socket_thread=new ThreadInfo[this->m_thread_count];
    for(qint32 index=0;index<this->m_thread_count;index++)
    {
        this->m_socket_thread[index].id=index;
        this->m_socket_thread[index].active_count=0;
        //启动线程
        this->m_socket_thread[index].msg_thread.start();
    }
}

FileServer::~FileServer()
{
    if(this->isListening())
    {
        this->close();
    }
    
    //释放申请的线程信息数组
    delete [] this->m_socket_thread;
    this->m_socket_thread=nullptr;
}

void FileServer::threadMonitor(QMap<qint32, quint32>& param_info)
{
    for(qint32 index=0;index<this->m_thread_count;index++)
    {
        param_info[index]=this->m_socket_thread[index].active_count;
    }
}

bool FileServer::run(quint16 port)
{
    if(this->isListening())
    {
        qDebug()<<"port("<<port<<")already listen,please close first."<<endl;
        return true;
    }

    if(this->listen(QHostAddress::Any,port))
    {
        qDebug()<<"listen "<<this->m_server_name<<"port("<<port<<") successful."<<endl;
        return true;
    }
    else
    {
        qDebug()<<"listen "<<"port("<<port<<") failed,please check the network port."<<endl;
        return false;
    }
}

void FileServer::socketClose(qint32 id)
{
    //槽函数,socket关闭的时候,将对应的线程的活跃socket数量减一
    this->m_socket_thread[id].active_count--;
}

void FileServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug()<<"new client connection:"<<socketDescriptor<<endl;
    qint32 thread_id=this->getMinActiveThread();
    //建立新的socket
    FileSocket* new_socket=new FileSocket(this->m_socket_thread[thread_id].id,socketDescriptor);
    connect(new_socket,SIGNAL(socketClose(qint32)),this,SLOT(socketClose(qint32)));
    //移入到线程中运行
    new_socket->moveToThread(&(this->m_socket_thread[thread_id].msg_thread));
    this->m_socket_thread[thread_id].active_count++;
}

qint32 FileServer::getMinActiveThread()
{
    qint32 min_id=0;
    for(qint32 index=1;index<this->m_thread_count;index++)
    {
        if(this->m_socket_thread[min_id].active_count>this->m_socket_thread[index].active_count)
        {
            min_id=index;
        }
    }

    return min_id;
}

#endif // FILESERVER_H

filesocket

//filesocket.h
#ifndef FILESOCKET_H
#define FILESOCKET_H

#include <QObject>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QByteArray>
#include <QFile>

//文件上传下载的字段定义
#define FILE_UPLOAD_HEADER             100
#define FILE_UPLOAD_POS                101
#define FILE_UPLOAD_TAIL               103
#define FILE_DOWNLOAD_HEADER           200
#define FILE_DOWNLOAD_CONTENT          202
#define FILE_DOWNLOAD_TAIL             203

//错误码定义
#define OK                             0
#define FILE_WRITE_ERROR               -1
#define FILE_OPEN_ERROR                -2
#define FILE_SEEK_ERROR                -3
#define FILE_ALREADY_EXISTS_ERROR      -4
#define RECV_DATA_TIMEOUT_ERROR        -5
#define RECV_UNKNOW_DATA_ERROR         -6
#define CONNECT_SERVER_ERROR           -7
#define UPLOAD_FILE_ERROR              -8
#define DOWNLOAD_FILE_ERROR            -10

class FileSocket : public QObject
{
    Q_OBJECT
public:
    explicit FileSocket(qint32 param_id,qintptr param_socketDescriptor,QObject *parent = nullptr);
    ~FileSocket();

signals:
    void socketClose(qint32); //当socket关闭的时候,向FileServer发送关闭信号

public slots:
    void socketError(QAbstractSocket::SocketError param_error);
    void socketDisconnect();
    
    //绑定readyRead信号,进行数据读取
    void fileRead();
    
    //文件数据处理
    void fileHandle(qint64 param_request_id,QMap<QString,QVariant>& param_qst_file,QMap<QString,QVariant>& param_rst_file,bool& reply);

protected:
    void paramInit();
    qint64 fileUploadHeader(QString filename,qint64& pos,QString& md5_value);
    qint64 fileUploadPos(qint64 file_pos);

    qint64 fileDownloadHeader(QString filename,qint64& pos,QString& md5_value,qint64& file_size);
    qint64 fileDownloadContent();

private:
    qint32 m_id;
    QTcpSocket m_socket;

    qint64 m_fileupload_state; //文件上传中间状态标志,分为头尾处理状态和文件数据传输状态。
    qint64 m_file_totalBytes;
    qint64 m_file_pos;
    qint64 m_req_id;

    QByteArray m_msgBytes;
    QFile m_local_file;
    qint64 m_status;
};
#endif // FILESOCKET_H

//filecosket.cpp
#include "filesocket.h"

#include <QDataStream>
#include <QByteArray>
#include <QMap>
#include <QVariant>
#include <QString>
#include <QCryptographicHash>

const QString g_root_dir=".";

FileSocket::FileSocket(qint32 param_id,qintptr param_socketDescriptor,QObject *parent) :
    QObject(parent),
    m_id(param_id),
    m_socket(this),
    m_fileupload_state(0),
    m_local_file(this)
{
    this->m_msgBytes.resize(0);
    this->paramInit();
    this->m_socket.setSocketDescriptor(param_socketDescriptor);

    connect(&(this->m_socket),SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(socketError(QAbstractSocket::SocketError)));
    //绑定readyRead信号,进行数据读取
    connect(&(this->m_socket),SIGNAL(readyRead()),this,SLOT(fileRead()));
}

FileSocket::~FileSocket()
{

}

void FileSocket::socketError(QAbstractSocket::SocketError param_error)
{
    qDebug()<<"socket error("<<param_error<<"): "<<this->m_socket.errorString()<<endl;
    this->m_fileupload_state=0;
    this->socketDisconnect();
}

void FileSocket::socketDisconnect()
{
    this->m_socket.disconnectFromHost();
    emit socketClose(this->m_id);
    this->deleteLater();
}

void FileSocket::fileRead()
{
    this->m_msgBytes.resize(0);
    this->m_msgBytes=this->m_socket.readAll();
    if(this->m_fileupload_state==0)
    {
        QDataStream file_in(&this->m_msgBytes,QIODevice::ReadOnly);
        QMap<QString,QVariant> param_qst_file;
        file_in>>this->m_req_id>>param_qst_file;

        QByteArray paramBytes;
        bool reply=true;
        QMap<QString,QVariant> param_rst_file;
        this->fileHandle(this->m_req_id,param_qst_file,param_rst_file,reply);
        if(reply==true)
        {
            QDataStream msg_out(&paramBytes,QIODevice::WriteOnly);
            msg_out<<qint64(this->m_req_id)<<param_rst_file;
            this->m_socket.write(paramBytes);
            this->m_socket.waitForBytesWritten();
        }
    }
    else
    {
        //文件上传的时候,开始数据写入
        this->m_file_totalBytes-=this->m_msgBytes.size();
        if(this->m_status!=OK)
        {
            return;
        }

        qint64 wrtieBytes=this->m_local_file.write(this->m_msgBytes);
        if(wrtieBytes==-1)
        {
            qDebug()<<"file write error"<<endl;
            this->m_status=FILE_WRITE_ERROR;
            return;
        }

        if(this->m_file_totalBytes==0)
        {
            this->m_local_file.close();
            QByteArray paramBytes;
            QMap<QString,QVariant> param_rst_file;
            param_rst_file[QString("reply_status")]=QVariant(this->m_status);

            QDataStream msg_out(&paramBytes,QIODevice::WriteOnly);
            msg_out<<qint64(FILE_UPLOAD_TAIL)<<param_rst_file;
            this->m_socket.write(paramBytes);
            this->m_socket.waitForBytesWritten();
            this->m_fileupload_state=0;
        }
    }
}

void FileSocket::fileHandle(qint64 param_request_id,QMap<QString,QVariant>& param_qst_file,QMap<QString,QVariant>& param_rst_file,bool& reply)
{
    switch (param_request_id)
    {
    case FILE_UPLOAD_HEADER:{
        this->paramInit();
        QString file_prjpath=param_qst_file[QString("file_prjpath")].toString();

        qint64 pos=0;
        QString md5_value;
        qint64 status=this->fileUploadHeader(file_prjpath,pos,md5_value);
        if(status==OK)
        {
            this->m_fileupload_state=0;
        }

        param_rst_file[QString("reply_status")]=QVariant(status);
        param_rst_file[QString("file_pos")]=QVariant(pos);
        param_rst_file[QString("file_md5")]=QVariant(md5_value);
        break;
    }
    case FILE_UPLOAD_POS:{

        qint64 file_pos=param_qst_file[QString("file_pos")].toInt();
        this->m_file_totalBytes=param_qst_file[QString("file_size")].toInt();

        qint64 status=this->fileUploadPos(file_pos);
        if(status==OK)
        {
            this->m_fileupload_state=1;
        }

        param_rst_file[QString("reply_status")]=QVariant(status);
        break;
    }
    case FILE_DOWNLOAD_HEADER:{
        this->paramInit();
        QString file_prjpath=param_qst_file[QString("file_prjpath")].toString();
        this->m_file_pos=param_qst_file[QString("file_pos")].toInt();
        QString file_md5_value=param_qst_file[QString("file_md5")].toString();

        qint64 status=this->fileDownloadHeader(file_prjpath,this->m_file_pos,file_md5_value,this->m_file_totalBytes);
        if(status==OK)
        {
            this->m_fileupload_state=0;
        }

        param_rst_file[QString("reply_status")]=QVariant(status);
        param_rst_file[QString("file_pos")]=QVariant(this->m_file_pos);
        param_rst_file[QString("file_size")]=QVariant(this->m_file_totalBytes);
        break;
    }
    case FILE_DOWNLOAD_CONTENT:{
        reply=false;
        this->fileDownloadContent();
        break;
    }
    case FILE_DOWNLOAD_TAIL:{
        qint64 status=OK;
        this->m_fileupload_state=0;
        param_rst_file[QString("reply_status")]=QVariant(status);
        break;
    }
    }
}

void FileSocket::paramInit()
{
    this->m_file_totalBytes=0;
    this->m_status=OK;
    this->m_file_pos=0;
}

qint64 FileSocket::fileUploadHeader(QString filename, qint64 &pos, QString &md5_value)
{
    QString filepath=QString("%1/%2").arg(g_root_dir).arg(filename);
    this->m_local_file.setFileName(filepath);
    if(this->m_local_file.exists()==false)
    {
        pos=0;
        return OK;
    }
    else
    {
        pos=this->m_local_file.size();
        if(pos==0)
        {
            return OK;
        }

        if(this->m_local_file.open(QIODevice::ReadOnly)==false)
        {
             pos=0;
             qDebug()<<"open file("<<this->m_local_file.fileName()<<") failed."<<endl;
             return FILE_OPEN_ERROR;
        }

        QCryptographicHash file_md5(QCryptographicHash::Md5);
        qint64 payloadSize=10*1024*1024;
        QByteArray file_data=this->m_local_file.read(payloadSize);
        while(!file_data.isEmpty())
        {
            file_md5.addData(file_data);
            file_data=this->m_local_file.read(payloadSize);
        }
        this->m_local_file.close();
        md5_value=QString(file_md5.result().toHex());

        return OK;
    }
}

qint64 FileSocket::fileUploadPos(qint64 file_pos)
{
    if(this->m_local_file.open(QIODevice::WriteOnly)==false)
    {
        qDebug()<<"open file("<<this->m_local_file.fileName()<<") failed."<<endl;
        return FILE_OPEN_ERROR;
    }

    if(this->m_local_file.seek(file_pos)==false)
    {
        qDebug()<<"seek file("<<this->m_local_file.fileName()<<") failed."<<endl;
        this->m_local_file.close();
        return FILE_SEEK_ERROR;
    }

    return OK;
}

qint64 FileSocket::fileDownloadHeader(QString filename, qint64 &pos, QString &md5_value, qint64 &file_size)
{
    this->m_local_file.setFileName(QString("%1/%2").arg(g_root_dir).arg(filename));
    if(this->m_local_file.open(QIODevice::ReadOnly)==false)
    {
        qDebug()<<"file open error"<<endl;
        return FILE_OPEN_ERROR;
    }
    file_size=this->m_local_file.size();

    if(pos==0)
    {
        this->m_local_file.close();
        return OK;
    }

    QCryptographicHash file_md5(QCryptographicHash::Md5);
    qint64 payloadSize=10*1024*1024;
    qint64 file_pos=pos;
    qint64 readBytes=0;
    while(file_pos>0)
    {
        readBytes=qMin(file_pos,payloadSize);
        QByteArray file_data=this->m_local_file.read(readBytes);
        file_md5.addData(file_data);
        file_pos-=readBytes;
    }
    this->m_local_file.close();

    if(QString(file_md5.result().toHex())!=md5_value)
    {
        pos=0;
    }
    file_size-=pos;

    return OK;
}

qint64 FileSocket::fileDownloadContent()
{
    if(this->m_local_file.open(QIODevice::ReadOnly)==false)
    {
        qDebug()<<"file open error"<<endl;
        return FILE_OPEN_ERROR;
    }
    this->m_local_file.seek(this->m_file_pos);

    qint64 payloadSize=1*1024*1024;
    while(this->m_file_totalBytes!=0)
    {
        QByteArray readData=this->m_local_file.read(qMin(this->m_file_totalBytes,payloadSize));
        this->m_file_totalBytes-=this->m_socket.write(readData);
        this->m_socket.waitForBytesWritten();
    }

    return OK;
}

客户端

即支持单个文件和文件列表的上传和下载,一个socket可连续进行文件的上传和下载。

客户端源码

//fileclient.h
#ifndef FILECLIENT_H
#define FILECLIENT_H

#include <QObject>
#include <QAbstractSocket>
#include <QTcpSocket>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QFile>

//文件上传下载字段定义
#define FILE_UPLOAD_HEADER             100
#define FILE_UPLOAD_POS                101
#define FILE_UPLOAD_TAIL               103
#define FILE_DOWNLOAD_HEADER           200
#define FILE_DOWNLOAD_CONTENT          202
#define FILE_DOWNLOAD_TAIL             203

//错误码定义
#define OK                             0
#define FILE_WRITE_ERROR               -1
#define FILE_OPEN_ERROR                -2
#define FILE_SEEK_ERROR                -3
#define FILE_ALREADY_EXISTS_ERROR      -4
#define RECV_DATA_TIMEOUT_ERROR        -5
#define RECV_UNKNOW_DATA_ERROR         -6
#define CONNECT_SERVER_ERROR           -7
#define UPLOAD_FILE_ERROR              -8
#define DOWNLOAD_FILE_ERROR            -10

class FileClient : public QObject
{
    Q_OBJECT
public:
    explicit FileClient(QString ip,quint16 port,QObject *parent = nullptr);
    ~FileClient();

public slots:
    qint64 filesUpload(QStringList filepath_list);
    qint64 fileUpload(QString filepath);

    qint64 filesDownload(QStringList filepath_list);
    qint64 fileDownload(QString filepath);

protected:
    qint64 fileUploadHeader(QString filepath);
    qint64 fileUploadPos();
    qint64 fileUploadContent();
    qint64 fileUploadTail();

    qint64 fileDownloadHeader(QString filepath);
    qint64 fileDownloadContent();
    qint64 fileDownloadTail();

    qint64 fileUploadRecvData(qint64 req_id,QMap<QString, QVariant>& recv_data);
    bool socketConnect();
    void paramInit();
    qint64 file_clc_md5(QString &md5_value);

private:
    QString m_ip;
    quint16 m_port;

    qint64 m_file_pos;
    qint64 m_payloadSize;
    qint64 m_file_total_size;

    QFile m_local_file;
    QTcpSocket m_socket;
};

#endif // FILECLIENT_H

//fileclient.cpp
#include "fileclient.h"

#include <QDataStream>
#include <QHostAddress>
#include <QFile>
#include <QCryptographicHash>
#include <QVariant>
#include <QFile>
#include <QFileInfo>

FileClient::FileClient(QString ip,quint16 port,QObject *parent) :
    QObject(parent),
    m_ip(ip),
    m_port(port),
    m_socket(this)
{

}

FileClient::~FileClient()
{
    if(this->m_socket.isOpen())
    {
        this->m_socket.close();
    }
}

qint64 FileClient::filesUpload(QStringList filepath_list)
{
    qint64 status=OK;
    foreach (QString filepath, filepath_list)
    {
        status=this->fileUpload(filepath);
        if(status!=OK)
        {
            return status;
        }
    }

    return status;
}

qint64 FileClient::fileUpload(QString filepath)
{
    qint64 status=OK;
    this->paramInit();

    status=this->fileUploadHeader(filepath);
    if(status==FILE_ALREADY_EXISTS_ERROR) //already exist
    {
        return OK;
    }
    else if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    status=this->fileUploadPos();
    if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    status=this->fileUploadContent();
    if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    status=this->fileUploadTail();
    if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    return status;
}

qint64 FileClient::filesDownload(QStringList filepath_list)
{
    qint64 status=OK;
    foreach (QString filepath, filepath_list)
    {
        status=this->fileDownload(filepath);
        if(status!=OK)
        {
            return status;
        }
    }

    return status;
}

qint64 FileClient::fileDownload(QString filepath)
{
    qint64 status=OK;
    this->paramInit();
    status=this->fileDownloadHeader(filepath);
    if(status==FILE_ALREADY_EXISTS_ERROR) //already exists
    {
        return OK;
    }
    else if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    status=this->fileDownloadContent();
    if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    status=this->fileDownloadTail();
    if(status!=OK)
    {
        this->m_socket.disconnectFromHost();
        return status;
    }

    return status;
}

qint64 FileClient::fileUploadRecvData(qint64 req_id, QMap<QString, QVariant>& recv_data)
{
    if(this->m_socket.waitForReadyRead()==false)
    {
        return RECV_DATA_TIMEOUT_ERROR;
    }

    qint64 recv_rsp_id=OK;
    QByteArray inblock=this->m_socket.readAll();
    QDataStream rsp_in(&inblock,QIODevice::ReadOnly);
    rsp_in>>recv_rsp_id>>recv_data;

    if(req_id!=recv_rsp_id)
    {
        return RECV_UNKNOW_DATA_ERROR;
    }

    return qint64(recv_data[QString("reply_status")].toInt());
}

qint64 FileClient::fileUploadHeader(QString filepath)
{
    if(this->m_socket.isOpen()==false)
    {
        if(this->socketConnect()==false)
        {
            qDebug()<<"socket connect failed:"<<this->m_socket.errorString()<<endl;
            return CONNECT_SERVER_ERROR;
        }
    }

    this->m_local_file.setFileName(filepath);
    if(this->m_local_file.open(QIODevice::ReadOnly)==false)
    {
        qDebug()<<"read file failed:"<<this->m_local_file.errorString()<<endl;
        return FILE_OPEN_ERROR;
    }
    this->m_file_total_size=this->m_local_file.size();
    this->m_local_file.close();

    QByteArray outblock;
    QDataStream file_out(&outblock,QIODevice::WriteOnly);
    QMap<QString,QVariant> file_header;
    file_header[QString("file_prjpath")]=QVariant(filepath.right(filepath.size()-filepath.lastIndexOf('/')-1));
    file_out<<qint64(FILE_UPLOAD_HEADER)<<file_header;

    this->m_socket.write(outblock);
    this->m_socket.waitForBytesWritten();

    QMap<QString, QVariant> rsp_msg;
    qint64 recv_status=this->fileUploadRecvData(FILE_UPLOAD_HEADER,rsp_msg);
    if(recv_status!=OK)
    {
        return recv_status;
    }
    this->m_file_pos=rsp_msg[QString("file_pos")].toInt();
    QString recv_md5=rsp_msg[QString("file_md5")].toString();

    if(this->m_file_pos==0)
    {
        return OK;
    }
    else
    {
        if(this->m_local_file.open(QIODevice::ReadOnly)==false)
        {
            return FILE_OPEN_ERROR;
        }

        qint64 readtotalBytes=0;
        qint64 payloadSize=10*1024*1024;
        QCryptographicHash clc_md5(QCryptographicHash::Md5);
        while(readtotalBytes<this->m_file_pos)
        {
            qint64 readBytes=qMin(payloadSize,this->m_file_pos-readtotalBytes);
            clc_md5.addData(this->m_local_file.read(readBytes));
            readtotalBytes+=readBytes;
        }
        this->m_local_file.close();

        if(QString(clc_md5.result().toHex())!=recv_md5)
        {
            this->m_file_pos=0;
        }

        this->m_file_total_size-=this->m_file_pos;
        if(this->m_file_total_size==0)
        {
            return FILE_ALREADY_EXISTS_ERROR;
        }
        else
        {
            return OK;
        }

    }
}

qint64 FileClient::fileUploadPos()
{
    QByteArray outblock;
    QDataStream file_out(&outblock,QIODevice::WriteOnly);
    QMap<QString,QVariant> file_header;
    file_header[QString("file_pos")]=QVariant(this->m_file_pos);
    file_header[QString("file_size")]=QVariant(this->m_file_total_size);
    file_out<<qint64(FILE_UPLOAD_POS)<<file_header;

    this->m_socket.write(outblock);
    this->m_socket.waitForBytesWritten();

    QMap<QString, QVariant> rsp_msg;
    qint64 recv_status=this->fileUploadRecvData(FILE_UPLOAD_POS,rsp_msg);

    return recv_status;
}

qint64 FileClient::fileUploadContent()
{
    if(this->m_socket.isOpen()==false)
    {
        return CONNECT_SERVER_ERROR;
    }

    if(this->m_local_file.open(QIODevice::ReadOnly)==false)
    {
        return FILE_OPEN_ERROR;
    }
    this->m_local_file.seek(this->m_file_pos);

    while(this->m_file_total_size!=0)
    {
        this->m_file_total_size-=this->m_socket.write(this->m_local_file.read(qMin(this->m_file_total_size,this->m_payloadSize)));
        this->m_socket.waitForBytesWritten();
    }

    return OK;
}

qint64 FileClient::fileUploadTail()
{
    if(this->m_socket.isOpen()==false)
    {
        return CONNECT_SERVER_ERROR;
    }

    QMap<QString, QVariant> rsp_msg;
    qint64 recv_status=this->fileUploadRecvData(FILE_UPLOAD_TAIL,rsp_msg);
    return recv_status;
}

qint64 FileClient::fileDownloadHeader(QString filepath)
{
    if(this->m_socket.isOpen()==false)
    {
        if(this->socketConnect()==false)
        {
            qDebug()<<"connect server error"<<endl;
            return CONNECT_SERVER_ERROR;
        }
    }

    qint64 file_pos=0;
    QString file_md5_value;
    this->m_local_file.setFileName(filepath);
    if(this->m_local_file.open(QIODevice::ReadOnly)==false)
    {
        file_pos=0;
    }
    else
    {
        file_pos=this->m_local_file.size();
        qint64 readtotalBytes=0;
        qint64 payloadSize=10*1024*1024;
        QCryptographicHash clc_md5(QCryptographicHash::Md5);
        while(readtotalBytes<file_pos)
        {
            qint64 readBytes=qMin(payloadSize,file_pos-readtotalBytes);
            clc_md5.addData(this->m_local_file.read(readBytes));
            readtotalBytes+=readBytes;
        }
        file_md5_value=QString(clc_md5.result().toHex());
        this->m_local_file.close();
    }

    QByteArray outblock;
    QDataStream file_out(&outblock,QIODevice::WriteOnly);
    QMap<QString,QVariant> file_header;
    file_header[QString("file_prjpath")]=QVariant(filepath);
    file_header[QString("file_pos")]=QVariant(file_pos);
    file_header[QString("file_md5")]=QVariant(file_md5_value);
    file_out<<qint64(FILE_DOWNLOAD_HEADER)<<file_header;

    this->m_socket.write(outblock);
    this->m_socket.waitForBytesWritten();

    QMap<QString, QVariant> rsp_msg;
    qint64 recv_status=this->fileUploadRecvData(FILE_DOWNLOAD_HEADER,rsp_msg);
    if(recv_status!=OK)
    {
        return recv_status;
    }

    this->m_file_pos=rsp_msg[QString("file_pos")].toInt();
    this->m_file_total_size=rsp_msg[QString("file_size")].toInt();

    if(0==this->m_file_total_size)
    {
        qDebug()<<"file already exist error"<<endl;
        return FILE_ALREADY_EXISTS_ERROR;
    }

    QByteArray outblock2;
    QDataStream file_out2(&outblock2,QIODevice::WriteOnly);
    QMap<QString,QVariant> file_header2;
    file_header2[QString("reply_status")]=QVariant(qint64(OK));
    file_out2<<qint64(FILE_DOWNLOAD_CONTENT)<<file_header2;

    this->m_socket.write(outblock2);
    this->m_socket.waitForBytesWritten();

    return OK;
}

qint64 FileClient::fileDownloadContent()
{ 
    if(this->m_local_file.open(QIODevice::WriteOnly)==false)
    {
        qDebug()<<"file open error:"<<this->m_local_file.fileName()<<endl;
        return FILE_OPEN_ERROR;
    }
    this->m_local_file.seek(this->m_file_pos);

    qint64 status=OK;
    while(this->m_file_total_size>0)
    {
        if(this->m_socket.waitForReadyRead()==false)
        {
            status=RECV_DATA_TIMEOUT_ERROR;
            break;
        }
        QByteArray inblock=this->m_socket.readAll();
        this->m_file_total_size-=inblock.size();
        if(status==OK)
        {
            if(this->m_local_file.write(inblock)==-1)
            {
                status=FILE_WRITE_ERROR;
            }
        }
    }
    this->m_local_file.close();

    if(status==OK)
    {
        QByteArray outblock2;
        QDataStream file_out2(&outblock2,QIODevice::WriteOnly);
        QMap<QString,QVariant> file_header2;
        file_header2[QString("reply_status")]=QVariant(qint64(OK));
        file_out2<<qint64(FILE_DOWNLOAD_TAIL)<<file_header2;

        this->m_socket.write(outblock2);
        this->m_socket.waitForBytesWritten();
    }

    return status;
}

qint64 FileClient::fileDownloadTail()
{
    QMap<QString, QVariant> rsp_msg;
    qint64 recv_status=this->fileUploadRecvData(FILE_DOWNLOAD_TAIL,rsp_msg);

    return recv_status;
}

bool FileClient::socketConnect()
{
    this->m_socket.close();

    this->m_socket.connectToHost(QHostAddress(this->m_ip),this->m_port);
    if(this->m_socket.waitForConnected()==false)
    {
        qDebug()<<"connect timeout:"<<this->m_ip<<this->m_port<<endl;
        return false;
    }

    return true;
}

void FileClient::paramInit()
{
    this->m_file_pos=0;
    this->m_payloadSize=1*1024*1024;//1MB
    this->m_local_file.close();
    this->m_file_total_size=0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • QT实现FTP上传文件

    本文实例为大家分享了QT实现FTP上传文件的具体代码,供大家参考,具体内容如下 两台电脑通过网线建立本地连接,保证网关在同一段: 服务器端打开ftp: 控制面板→程序→启用或关闭windows功能→windows功能→Internet信息服务启用“FTP服务”FTP扩展性” IIS管理控制台” 开始屏幕的搜索中输入“IIS”,然后点击打开“IIS管理器”打开“IIS管理器”后,在左栏的“网站”上点击右键,打开“添加FTP站点”然后按照提示填写站点信息点击“下一步”,按照下图提示,设置“绑定和SS

  • Qt实现FTP的上传和下载的实例代码

    为了方便网络编程,Qt 提供了 Network 模块.该模块包含了许多类,本文介绍了Qt实现FTP的上传和下载,分享给大家 本来想简单抄抄书,随便手写个Ftp客户端的,结果发现教材上的是基于Qt4的QFtp类库,而在Qt5中取消了这一个类库(同时也取消了QHttp等的类),取而代之的是QNetworkAccessManager 这个类,把这些杂货全都揽下来了,据说是因为之前的两个类有重复而且效率有问题balabala.于是就百度了一下,发现百度上要么讲的不全,要么就是要去下一个由热心网民重新封装

  • Qt QFtp客户端实现上传下载文件

    目录 1.简介 2.用到的主要类 2.1QNetworkReply 2.2QNetworkRequest 3.示例 3.1本地搭建一个FTP服务器. 3.2示例 1.简介 实现FTP客户端有几种方式. Qt4 QFtp类 Qt5 QNetworkAccessManager类 QNetworkAccessManager支持大多数的网络协议,比如http.ftp等,这里主要讲解QNetworkAccessManager实现的FTP客户端. 需要添加 Qt += network 模块. 2.用到的主要

  • 基于QT实现文件上传和下载功能

    本文实例为大家分享了基于QT实现文件上传和下载的具体代码,供大家参考,具体内容如下 功能 支持文件上传功能 支持文件下载功能 支持断点续传功能 支持连续多个文件的上传下载 文件上传下载流程 在确认断点的时候会利用md5进行数据校验,防止数据发生更改. 服务端 采用多线程的Reactor模式.即一个线程对应多个filesocket进行文件上传下载.线程个数可设置,默认为1. FileServer 继承QTcpServer,实现incomingConnection虚函数.当有新的连接到来时,会创建F

  • Retrofit+Rxjava实现文件上传和下载功能

    Retrofit简介: 在Android API4.4之后,Google官方使用了square公司推出的okHttp替换了HttpClient的请求方式.后来square公司又推出了基于okHttp的网络请求框架:Retrofit. 什么是 RxJava? RxJava 是一个响应式编程框架,采用观察者设计模式.所以自然少不了 Observable 和 Subscriber 这两个东东了. RxJava 是一个开源项目,地址:https://github.com/ReactiveX/RxJava

  • MyBatis与SpringMVC相结合实现文件上传、下载功能

    环境:maven+SpringMVC + Spring + MyBatis + MySql 本文主要说明如何使用input上传文件到服务器指定目录,或保存到数据库中:如何从数据库下载文件,和显示图像文件并实现缩放. 将文件存储在数据库中,一般是存文件的byte数组,对应的数据库数据类型为blob. 首先要创建数据库,此处使用MySql数据库. 注意:文中给出的代码多为节选重要片段,并不齐全. 1. 前期准备 使用maven创建一个springMVC+spring+mybatis+mysql的项目

  • spring mvc实现文件上传与下载功能

    本文实例为大家分享了spring mvc实现文件上传与下载功能的具体代码,供大家参考,具体内容如下 文件上传 在pom.xml中引入spring mvc以及commons-fileupload的相关jar <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <v

  • Django实现文件上传和下载功能

    本文实例为大家分享了Django下完成文件上传和下载功能的具体代码,供大家参考,具体内容如下 一.文件上传 Views.py def upload(request): if request.method == "POST": # 请求方法为POST时,进行处理 myFile = request.FILES.get("myfile", None) # 获取上传的文件,如果没有文件,则默认为None if not myFile: return HttpResponse(

  • node.js express框架实现文件上传与下载功能实例详解

    本文实例讲述了node.js express框架实现文件上传与下载功能.分享给大家供大家参考,具体如下: 背景 昨天吉视传媒的客户对IPS信息发布系统又提了一个新需求,就是发布端发送消息时需要支持附件的上传,而接收端可以对发布端上传的附件进行下载:接收端回复消息时也需要支持上传附件,发布端可以对所有接收端上传的附件进行打包下载. 功能实现 前台部分 前台使用webUploader插件即可,这是百度开发的一款文件上传组件,具体使用查看它的API即可.这个项目之前开发的时候前台使用了angular.

  • 详解JavaWeb如何实现文件上传和下载功能

    目录 1. 文件传输原理及介绍 2. JavaWeb文件上传 2.1我们用一个新的方式创建项目 2.2 导包 2.3 实用类介绍 2.4 pom.xml导入需要的依赖 2.5 index.jsp 2.6 info.jsp 2.7 FileServlet 2.8 配置Servlet 2.9 测试结果 3. SpringMVC文件上传和下载 3.1 上传 3.2 下载 1. 文件传输原理及介绍 2. JavaWeb文件上传 2.1我们用一个新的方式创建项目 空项目会直接弹出框 把jdk版本设置好 点

  • SpringBoot+微信小程序实现文件上传与下载功能详解

    目录 1.文件上传 1.1 后端部分 1.2 小程序前端部分 1.3 实现效果 2.文件下载 2.1 后端部分 2.2 小程序前端部分 2.3 实现效果 1.文件上传 1.1 后端部分 1.1.1 引入Apache Commons FIleUpload组件依赖 <!--文件上传与下载相关的依赖--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fil

  • JavaWeb Servlet实现文件上传与下载功能实例

    目录 前言 项目准备 文件上传 前台页面 文件下载 资源准备 超链接下载 后台实现下载 总结 前言 在上网的时候我们常常遇到文件上传的情况,例如上传头像.上传资料等:当然除了上传,遇见下载的情况也很多,接下来看看我们 servlet 中怎么实现文件的上传和下载. 项目准备 idea:2020.1 jdk:1.8 tomcat:10 项目模板:java Enterprise–>Web Application 文件上传 文件上传涉及到前台页面的编写和后台服务器端代码的编写,前台发送文件,后台接收并保

  • SpringBoot实现文件上传与下载功能的示例代码

    目录 Spring Boot文件上传与下载 举例说明 1.引入Apache Commons FileUpload组件依赖 2.设置上传文件大小限制 3.创建选择文件视图页面 4.创建控制器 5.创建文件下载视图页面 6.运行 Spring Boot文件上传与下载 在实际的Web应用开发中,为了成功上传文件,必须将表单的method设置为post,并将enctype设置为multipart/form-data.只有这种设置,浏览器才能将所选文件的二进制数据发送给服务器. 从Servlet 3.0开

随机推荐