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