QT 实现选择文件并上传显示进度条,tcp传输

这个博客展示了如何使用Qt库实现文件选择、上传功能,并在客户端显示上传进度条。客户端通过TCP连接发送文件到服务器,服务器接收文件并保存。在文件传输过程中,利用QDataStream处理数据流,更新进度条以反映文件发送状态。
摘要由CSDN通过智能技术生成

 Qt 实现选择文件 上传,进度条,客户端 .cpp:

#include "filesetdialog.h"
#include "ui_filesetdialog.h"
#include <string>   //string
#include <iostream> // cout
#include <QString>
#include <QTextCodec>
FileSetDialog::FileSetDialog(QWidget *parent): QDialog(parent),
      ui(new Ui::FileSetDialog)
{
    ui->setupUi(this);

    this->initTCP();

    //文件传送相关变量初始化
    //文件传送相关变量初始化
    perDataSize = 64 * 1024;
    totalBytes = 0;
    bytestoWrite = 0;
    bytesWritten = 0;
    bytesReceived = 0;
    filenameSize = 0;


    ui->buttonBox->button(QDialogButtonBox::Cancel)->setText("关闭");

    connect(this->ui->pushButton_openFile, SIGNAL(clicked()), this, SLOT(selectFile()));
    connect(this->ui->pushButton_sendFile, SIGNAL(clicked()), this, SLOT(sendFile()));
}

FileSetDialog::~FileSetDialog()
{
    delete ui;
}

void FileSetDialog::initTCP()
{
    this->tcpSocket = new QTcpSocket(this);
}

void FileSetDialog::disconnectServer()
{

}

void FileSetDialog::selectFile()
{
    this->fileSocket = new QTcpSocket(this);
    fileSocket->abort();
    fileSocket->connectToHost("127.0.0.1", 8888);
    // 文件传送进度条更新
    connect(fileSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(updateFileProgress(qint64)));


    this->ui->progressBar->setValue(0);
    this->filename = QFileDialog::getOpenFileName(this, "Open a file", "/", "files (*)");
    ui->lineEdit_filename->setText(filename);//文件名
}

void FileSetDialog::sendFile()
{
    this->localFile = new QFile(filename);
    if (!localFile->open(QFile::ReadOnly))
    {
        ui->textEdit->setText(tr("FileSetDialog:open file error!"));
        return;
    }
    // 获取文件大小
    this->totalBytes = localFile->size();

//    qDebug() << "this->totalBytes====" << this->totalBytes;

    //QByteArray t = localFile->readAll();//获取文件内容展示出来
    //ui->textEdit->setText(QString(t));

    QDataStream sendout(&outBlock, QIODevice::WriteOnly);
    sendout.setVersion(QDataStream::Qt_4_8);
    QString currentFileName = filename.right(filename.size() - filename.lastIndexOf('/') - 1);

    qDebug() << sizeof(currentFileName);
    // 保留总代大小信息空间、文件名大小信息空间、文件名
    sendout << qint64(0) << qint64(0) << currentFileName;
    totalBytes += outBlock.size();
    sendout.device()->seek(0);
    sendout << totalBytes << qint64((outBlock.size() - sizeof(qint64)* 2));

    bytestoWrite = totalBytes - fileSocket->write(outBlock);
    outBlock.resize(0);
}

void FileSetDialog::updateFileProgress(qint64 numBytes)
{
    // 已经发送的数据大小
    bytesWritten += (int)numBytes;

    // 如果已经发送了数据
    if (bytestoWrite > 0)
    {
        outBlock = localFile->read(qMin(bytestoWrite, perDataSize));
        // 发送完一次数据后还剩余数据的大小
        bytestoWrite -= ((int)fileSocket->write(outBlock));
        // 清空发送缓冲区
        outBlock.resize(0);
    }
    else
        localFile->close();

//    qDebug() << "totalBytes==" << totalBytes << "bytesWritten== " << bytesWritten;
    // 更新进度条
    this->ui->progressBar->setMaximum(totalBytes);
    this->ui->progressBar->setValue(bytesWritten);

    // 如果发送完毕
    if (bytesWritten >= totalBytes)
    {
        localFile->close();
        disconnect(fileSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(updateFileProgress(qint64)));
        delete localFile;
        bytesWritten = 0;
        //fileSocket->close();
    }
}



.h:

#ifndef FILESETDIALOG_H
#define FILESETDIALOG_H

#include <QDialog>
#include <QtWidgets/QWidget>
#include <QtNetwork>
#include <QHostAddress>
#include <QMessageBox>
#include <QDataStream>
#include <QByteArray>
#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <QFileDialog>
#include <QAbstractButton>

namespace Ui {
class FileSetDialog;
}

class FileSetDialog : public QDialog
{
    Q_OBJECT

public:
    explicit FileSetDialog(QWidget *parent = nullptr);
    ~FileSetDialog();

    void initTCP();
    void newConnect();

private slots:
    // 与服务器断开连接
    void disconnectServer();
    // 浏览文件
    void selectFile();
    // 发送文件
    void sendFile();
    // 更新文件发送进度
    void updateFileProgress(qint64);

private:
    Ui::FileSetDialog *ui;

    QTcpSocket *tcpSocket;
    QTcpSocket *fileSocket;

    // 文件传送
    QFile *localFile;
    // 文件大小
    qint64 totalBytes;      //文件总字节数
    qint64 bytesWritten;    //已发送的字节数
    qint64 bytestoWrite;    //尚未发送的字节数
    qint64 filenameSize;    //文件名字的字节数
    qint64 bytesReceived;   //接收的字节数
    ///每次发送数据大小
    qint64 perDataSize;
    QString filename;
    ///数据缓冲区
    QByteArray inBlock;
    QByteArray outBlock;

    QString selectPath ="";
};

#endif // FILESETDIALOG_H

服务端:

.cpp:

#include "filemanagment.h"
#include <QDataStream>
#include <QMessageBox>
#include <QString>
#include <QByteArray>
#include <QApplication>

#include <QTextCodec>

FileManagment * FileManagment::widget=nullptr;
FileManagment::FileManagment(QWidget *parent) : QWidget(parent)
{
    // 文件传送套接字
    this->filesocket = new QTcpSocket(this);
    this->fileserver = new QTcpServer(this);
    this->fileserver->listen(QHostAddress::Any,8888);
    connect(this->fileserver,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));

    // 文件传送相关变量初始化
    bytesReceived = 0;
    totalBytes = 0;
    filenameSize = 0;
}

FileManagment *FileManagment::getFileManagment()
{
    if(widget==nullptr)
    {
        widget = new FileManagment();
    }
    return widget;
}

FileManagment::~FileManagment()
{
    close();
//    delete m_sever;
}


void FileManagment::acceptFileConnection()
{
    bytesWritten = 0;
    //每次发送数据大小为64kb
    perDataSize = 64*1024;
    this->filesocket = this->fileserver->nextPendingConnection();
    //接受文件
    connect(filesocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));
    connect(filesocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(updateFileProgress(qint64)));
    connect(filesocket,SIGNAL(bytesWritten(qint64)),this,SLOT(displayError(QAbstractSocket::SocketError socketError)));

    qDebug() << "acceptFileConnection  ";
}

void FileManagment::updateFileProgress()
{
    QDataStream inFile(this->filesocket);
    inFile.setVersion(QDataStream::Qt_4_8);

    //如果接收到的数据小于16个字节,保存到来的文件头结构
    if(bytesReceived <= sizeof(qint64)*2)
    {
        if((filesocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
        {
            inFile>>totalBytes>>filenameSize;
            bytesReceived += sizeof(qint64)*2;
        }
        if((filesocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
        {
            inFile>>filename;
            bytesReceived += filenameSize;
            //创建同名文件
            QString filePath = QApplication::applicationDirPath() + "/../../S_Video_v3/fileData";
            qDebug() << " 文件夹filePath!" << filePath;
            QDir dir(filePath);

//            QDir *temp = new QDir;
            bool exist = dir.exists(filePath);
            if(exist)
                qDebug() << "文件夹已经存在!";
            else
            {
                bool ok = dir.mkdir(filePath);
                if( ok )
                qDebug() << "文件夹不存在,创建成功!";
            }

            filePath = dir.absolutePath() + QString("/%1").arg(filename);
            localFile = new QFile(filePath);

//            //            接收的文件放在指定目录下
//            filename = "ClientData/"+filename;
//            localFile = new QFile(filename);
            if(!localFile->open(QFile::WriteOnly))
            {
                qDebug()<<"Server::open file error!";
                return;
            }
        }
        else
            return;
    }
    //    /如果接收的数据小于总数据,则写入文件
    if(bytesReceived < totalBytes)
    {
        bytesReceived += filesocket->bytesAvailable();
        inBlock = filesocket->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    //    数据接收完成时
    if(bytesReceived == totalBytes)
    {
        //        this->ui.browser->append("Receive file successfully!");
        bytesReceived = 0;
        totalBytes = 0;
        filenameSize = 0;
        localFile->close();
        //filesocket->close();
    }
}

void FileManagment::displayError(QAbstractSocket::SocketError socketError)
{
    qDebug()<< "displayError--" << socket->errorString();
    socket->close();
}

 .h:

#ifndef FILEMANAGMENT_H
#define FILEMANAGMENT_H
#include <QString>
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
#include <QWidget>
#include <QProcess>
#include <iostream>
#include <QThread>
using namespace std;


class FileManagment: public QWidget
{
    Q_OBJECT
public:
    explicit FileManagment(QWidget *parent = nullptr);
    ~FileManagment();
    static FileManagment * getFileManagment();

    QTcpServer *server;
    QTcpSocket *socket;
    QTcpServer *fileserver;
    QTcpSocket *filesocket;


private slots:
    void acceptFileConnection();
    void updateFileProgress();
    void displayError(QAbstractSocket::SocketError socketError);

private:
    static FileManagment *widget;
//    传送文件相关变量
    qint64 totalBytes;
    qint64 bytesReceived;
    qint64 bytestoWrite;
    qint64 bytesWritten;
    qint64 filenameSize;
    QString filename;
    ///每次发送数据大小
    qint64 perDataSize;
    QFile *localFile;
//    本地缓冲区
    QByteArray inBlock;
    QByteArray outBlock;
};

#endif // FILEMANAGMENT_H

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,针对您的问题,我可以提供以下代码示例来实现: ```cpp #include <QFile> #include <QTextCodec> #include <QTextStream> #include <QProgressDialog> #include <QEventLoop> void readFile(const QString& fileName, const QString& codecName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { // 文件打开失败 return; } QTextCodec* codec = QTextCodec::codecForName(codecName.toUtf8()); QTextStream in(&file); in.setCodec(codec); int fileSize = file.size(); // 获取文件大小 int bytesRead = 0; // 已读取的字节数 QProgressDialog progress("Reading file...", "Cancel", 0, fileSize); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(0); progress.show(); QEventLoop loop; QObject::connect(&progress, SIGNAL(canceled()), &loop, SLOT(quit())); while (!in.atEnd()) { if (progress.wasCanceled()) { // 用户点击取消按钮 loop.exec(); // 暂停读取文件 if (progress.wasCanceled()) { // 用户再次点击取消按钮,退出循环 break; } } QString line = in.readLine(); bytesRead += line.size() + 1; // 包括换行符的长度 progress.setValue(bytesRead); // 处理读取到的数据 // ... } file.close(); } ``` 在这个示例中,我们首先打开文件,并使用指定编码的QTextCodec对象来设置QTextStream的编码。然后,我们获取文件大小,并创建一个QProgressDialog对象来显示进度条。在进入while循环后,我们不断读取文件数据,并更新进度条的value属性。在每次读取数据后,我们都会检查用户是否点击了取消按钮,如果是,则调用QEventLoop类的exec()方法暂停读取文件的过程,并等待用户再次点击继续按钮。如果用户再次点击取消按钮,则退出循环。在循环结束后,我们关闭文件并结束函数的执行。 希望这个示例对您有所帮助!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值