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

 更新时间:2022年8月18日 19:20  点击:508 作者:skynetkang

本文实例为大家分享了基于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;
}

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

原文出处:https://blog.csdn.net/qq_33232152/article/details/125605457

[!--infotagslink--]

相关文章

  • C#实现HTTP下载文件的方法

    这篇文章主要介绍了C#实现HTTP下载文件的方法,包括了HTTP通信的创建、本地文件的写入等,非常具有实用价值,需要的朋友可以参考下...2020-06-25
  • Php文件上传类class.upload.php用法示例

    本文章来人大家介绍一个php文件上传类的使用方法,期望此实例对各位php入门者会有不小帮助哦。 简介 Class.upload.php是用于管理上传文件的php文件上传类, 它可以帮...2016-11-25
  • PHP文件上传一些小收获

    又码了一个周末的代码,这次在做一些关于文件上传的东西。(PHP UPLOAD)小有收获项目是一个BT种子列表,用户有权限上传自己的种子,然后配合BT TRACK服务器把种子的信息写出来...2016-11-25
  • jQuery实现简单的文件上传进度条效果

    本文实例讲述了jQuery实现文件上传进度条效果的代码。分享给大家供大家参考。具体如下: 运行效果截图如下:具体代码如下:<!DOCTYPE html><html><head><meta charset="utf-8"><title>upload</title><link rel="stylesheet...2015-11-24
  • php文件上传你必须知道的几点

    本篇文章主要说明的是与php文件上传的相关配置的知识点。PHP文件上传功能配置主要涉及php.ini配置文件中的upload_tmp_dir、upload_max_filesize、post_max_size等选项,下面一一说明。打开php.ini配置文件找到File Upl...2015-10-21
  • php实现文件下载实例分享

    举一个案例:复制代码 代码如下:<?phpclass Downfile { function downserver($file_name){$file_path = "./img/".$file_name;//转码,文件名转为gb2312解决中文乱码$file_name = iconv("utf-8","gb2312",$file_name...2014-06-07
  • EXCEL数据上传到SQL SERVER中的简单实现方法

    EXCEL数据上传到SQL SERVER中的方法需要注意到三点!注意点一:要把EXCEL数据上传到SQL SERVER中必须提前把EXCEL传到服务器上.做法: 在ASP.NET环境中,添加一个FileUpload上传控件后台代码的E.X: 复制代码 代码如下: if...2013-09-23
  • Visual Studio 2015下载和安装图文教程

    这篇文章主要为大家详细介绍了Visual Studio 2015下载和安装图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
  • DWVA上传漏洞挖掘的测试例子

    DVWA (Dam Vulnerable Web Application)DVWA是用PHP+Mysql编写的一套用于常规WEB漏洞教学和检测的WEB脆弱性测试程序。包含了SQL注入、XSS、盲注等常见的一些安全漏洞...2016-11-25
  • js实现上传图片及时预览

    这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
  • PHP swfupload图片上传的实例代码

    PHP代码如下:复制代码 代码如下:if (isset($_FILES["Filedata"]) || !is_uploaded_file($_FILES["Filedata"]["tmp_name"]) || $_FILES["Filedata"]["error"] != 0) { $upload_file = $_FILES['Filedata']; $fil...2013-10-04
  • 百度编辑器ueditor修改图片上传默认路径

    本案例非通用,仅作笔记以备用 修改后的结果是 百度编辑器里上传的图片路径为/d/file/upload1...2014-07-03
  • SpringMVC文件上传原理及实现过程解析

    这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
  • 借助FileReader实现将文件编码为Base64后通过AJAX上传

    这篇文章主要介绍了借助FileReader实现将文件编码为Base64后通过AJAX上传的方法,包括后端对文件数据解码并保存的PHP代码,需要的朋友可以参考下...2015-12-25
  • PHP的APC模块实现上传进度条

    APC模块,它的全称是Alternative PHP Cache。APC可以将所有PHP代码会被缓存起来, 另外它可提供一定的内存缓存功能.但是这个功能并不是十分完美,有报告说如果频繁使用APC缓存的写入功能,会导致不可预料的错误.如果想使用...2015-10-30
  • jQuery+ajax简单实现文件上传的方法

    这篇文章主要介绍了jQuery+ajax简单实现文件上传的方法,结合实例形式简单分析了jQuery基于ajax的post方法进行文件传输及asp.net后台处理技巧,需要的朋友可以参考下...2016-06-12
  • smartupload实现文件上传时获取表单数据(推荐)

    这篇文章主要介绍了smartupload实现文件上传时获取表单数据的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2017-01-09
  • Qt 使用Poppler实现pdf阅读器的示例代码

    下面小编就为大家分享一篇Qt 使用Poppler实现pdf阅读器的示例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-25
  • 适用于初学者的简易PHP文件上传类

    本文实例讲述了PHP多文件上传类,分享给大家供大家参考。具体如下:<&#63;phpclass Test_Upload{ protected $_uploaded = array(); protected $_destination; protected $_max = 1024000; protected $_messages =...2015-10-30
  • Java实现将图片上传到webapp路径下 路径获取方式

    这篇文章主要介绍了Java实现将图片上传到webapp路径下 路径获取方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-11-12