QT實現(xiàn)文件傳輸功能
本文實例為大家分享了QT實現(xiàn)文件傳輸功能的具體代碼,供大家參考,具體內(nèi)容如下
過程如下:
1、服務(wù)器端設(shè)置監(jiān)聽套接字,開始監(jiān)聽;
2、客戶端在連接成功時開始傳送文件,有connected()信號連接send()槽,send()發(fā)送文件頭信息,包括文件名、文件總大小和文件名大小等;
3、傳送完文件頭信息時開始傳送文件內(nèi)容,有bytesWritten(qint64)信號連接到goOnSend(qint64)槽,前者是當想套接字寫入數(shù)據(jù)時會出發(fā)的信號,即當已經(jīng)想套接字寫入數(shù)據(jù),就繼續(xù)傳送數(shù)據(jù),有send()傳送文件頭信息開始觸發(fā),直到文件傳完為止。
4、在服務(wù)器端,首先接收文件頭信息,然后讀取文件名來用新建文件的方式打開一個文件,然后讀取文件名即文件等大小信息,用來更新進度條和繼續(xù)接收數(shù)據(jù);
5、實現(xiàn)循環(huán)傳輸,在客戶端,因為第一次send()是由connected()信號觸發(fā)的,之后的每次傳送應(yīng)該手動調(diào)用send();在服務(wù)器端,在有新數(shù)據(jù)到達時,會判斷是否為頭文件,因此在每次文件傳完的時候?qū)yteReceived重置為0,即下一次再接收到數(shù)據(jù)的時候依據(jù)byteReceived判斷的結(jié)果就是一個新文件了。
客戶端代碼:
#ifndef WIDGET_H ?
#define WIDGET_H ?
??
#include <QWidget> ?
#include <QTcpSocket> ?
#include <QFile> ?
#include <string> ?
??
namespace Ui { ?
class Widget; ?
} ?
??
class Widget : public QWidget ?
{ ?
? ? Q_OBJECT ?
??
public: ?
? ? explicit Widget(QWidget *parent = 0); ?
? ? ~Widget(); ?
? ? ??
private: ?
? ? Ui::Widget *ui; ?
??
? ? QTcpSocket *tcpClient; ?
? ? QFile *localFile; ?
? ? QString fileName; ?//文件名 ?
??
? ? QByteArray outBlock; ?//分次傳 ?
? ? qint64 loadSize; ?//每次發(fā)送數(shù)據(jù)的大小 ?
? ? qint64 byteToWrite; ?//剩余數(shù)據(jù)大小 ?
? ? qint64 totalSize; ?//文件總大小 ?
??
? ? int sendTimes; ?//用來標記是否為第一次發(fā)送,第一次以后連接信號觸發(fā),后面的則手動調(diào)用 ?
??
private slots: ?
? ? void send(); ?//傳送文件頭信息 ?
? ? void goOnSend(qint64); ?//傳送文件內(nèi)容 ?
? ? void on_openPushButton_clicked(); ?
? ? void on_sendPushButton_clicked(); ?
}; ?
??
#endif // WIDGET_H ?widget.cpp
#include "widget.h" ?
#include "ui_widget.h" ?
#include <QHostAddress> ?
#include <QTextCodec> ?
#include <QFileDialog> ?
??
Widget::Widget(QWidget *parent) : ?
? ? QWidget(parent), ?
? ? ui(new Ui::Widget) ?
{ ?
? ? ui->setupUi(this); ?
??
? ? ui->progressLabel->hide(); ?
? ? QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));
??
? ? tcpClient = new QTcpSocket(this); ?
? ? sendTimes = 0; ?
??
? ? connect(tcpClient, SIGNAL(connected()), this, SLOT(send())); ?//當連接成功時,就開始傳送文件 ?
? ? connect(tcpClient, SIGNAL(bytesWritten(qint64)), this, SLOT(goOnSend(qint64))); ??
} ?
??
void Widget::send() ?//發(fā)送文件頭信息 ?
{ ?
? ? byteToWrite = localFile->size(); ?//剩余數(shù)據(jù)的大小 ?
? ? totalSize = localFile->size(); ?
??
? ? loadSize = 4*1024; ?//每次發(fā)送數(shù)據(jù)的大小 ?
??
? ? QDataStream out(&outBlock, QIODevice::WriteOnly); ?
? ? QString currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1); ?
??
? ? out<<qint64(0)<<qint64(0)<<currentFileName; ?
??
? ? totalSize += outBlock.size(); ?//總大小為文件大小加上文件名等信息大小 ?
? ? byteToWrite += outBlock.size(); ?
??
? ? out.device()->seek(0); ?//回到字節(jié)流起點來寫好前面連個qint64,分別為總大小和文件名等信息大小 ?
? ? out<<totalSize<<qint64(outBlock.size()); ?
??
? ? tcpClient->write(outBlock); ?//將讀到的文件發(fā)送到套接字 ?
??
? ? ui->progressLabel->show(); ?
? ? ui->sendProgressBar->setMaximum(totalSize); ?
? ? ui->sendProgressBar->setValue(totalSize - byteToWrite); ?
} ?
??
void Widget::goOnSend(qint64 numBytes) ?//開始發(fā)送文件內(nèi)容 ?
{ ?
? ? byteToWrite -= numBytes; ?//剩余數(shù)據(jù)大小 ?
? ? outBlock = localFile->read(qMin(byteToWrite, loadSize)); ?
? ? tcpClient->write(outBlock); ?
??
? ? ui->sendProgressBar->setMaximum(totalSize); ?
? ? ui->sendProgressBar->setValue(totalSize - byteToWrite); ?
??
? ? if(byteToWrite == 0) ?//發(fā)送完畢 ?
? ? ? ? ui->sendStatusLabel->setText(tr("文件發(fā)送完畢!")); ?
} ?
??
Widget::~Widget() ?
{ ?
? ? delete ui; ?
} ?
??
void Widget::on_openPushButton_clicked() ?//打開文件并獲取文件名(包括路徑) ?
{ ?
? ? ui->sendStatusLabel->setText(tr("正在打開文件...")); ?
? ? ui->sendProgressBar->setValue(0); ?//非第一次發(fā)送 ?
??
? ? loadSize = 0; ?
? ? byteToWrite = 0; ?
? ? totalSize = 0; ?
? ? outBlock.clear(); ?
??
? ? fileName = QFileDialog::getOpenFileName(this); ?
? ? localFile = new QFile(fileName); ?
? ? localFile->open(QFile::ReadOnly); ?
??
? ? ui->sendStatusLabel->setText(tr("已打開文件 %1").arg(fileName)); ?
} ?
??
void Widget::on_sendPushButton_clicked() ?
{ ?
? ? if(sendTimes == 0) ?//只有第一次發(fā)送的時候,是發(fā)生在連接產(chǎn)生信號connect時 ?
? ? { ?
? ? ? ? tcpClient->connectToHost(QHostAddress("192.168.1.137"), 1000); ?
? ? ? ? sendTimes = 1; ? ?
? ? } ?
? ? else ?
? ? ? ? send(); ?//第一次發(fā)送的時候是由connectToHost出發(fā)connect信號才能調(diào)用send,第二次之后就需要調(diào)用send了 ?
??
? ? ui->sendStatusLabel->setText(tr("正在發(fā)送文件 %1").arg(fileName)); ?
} ?服務(wù)端代碼:
widget.h
#ifndef WIDGET_H ?
#define WIDGET_H ?
??
#include <QWidget> ?
#include <QtNetwork/QTcpServer> ?
#include <QtNetwork/QTcpSocket> ?
#include <QFile> ?
#include <QString> ?
??
namespace Ui { ?
class Widget; ?
} ?
??
class Widget : public QWidget ?
{ ?
? ? Q_OBJECT ?
? ? ??
public: ?
? ? explicit Widget(QWidget *parent = 0); ?
? ? ~Widget(); ?
? ? ??
private: ?
? ? Ui::Widget *ui; ?
??
? ? QTcpServer *server; ?
? ? QTcpSocket *receivedSocket; ?
? ? QFile *newFile; ?
??
? ? QByteArray inBlock; ?
? ? QString fileName; ?
? ? qint64 totalSize; ?//總共需要發(fā)送的文件大?。ㄎ募?nèi)容&文件名信息) ?
? ? qint64 byteReceived; ?//已經(jīng)發(fā)送的大小 ?
??
private slots: ?
? ? void acceptConnection(); ?
? ? void readClient(); ?
? ? void on_pushButton_clicked(); ?
}; ?
??
#endif // WIDGET_H ?widget.cpp
#include "widget.h" ?
#include "ui_widget.h" ?
#include <QTextCodec> ?
??
Widget::Widget(QWidget *parent) : ?
? ? QWidget(parent), ?
? ? ui(new Ui::Widget) ?
{ ?
? ? ui->setupUi(this); ?
? ? ui->progressLabel->hide(); ??
? ? QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));
} ?
??
void Widget::acceptConnection() ?
{ ?
? ? ui->receivedStatusLabel->setText(tr("已連接,正在準備接收文件!")); ?
??
? ? receivedSocket = server->nextPendingConnection(); ?
? ? connect(receivedSocket, SIGNAL(readyRead()), this, SLOT(readClient())); ?
} ?
??
void Widget::readClient() ?
{ ?
? ? ui->receivedStatusLabel->setText(tr("正在接收文件...")); ?
??
? ? if(byteReceived == 0) ?//才剛開始接收數(shù)據(jù),此數(shù)據(jù)為文件信息 ?
? ? { ?
? ? ? ? ui->receivedProgressBar->setValue(0); ?
??
? ? ? ? QDataStream in(receivedSocket); ?
? ? ? ? in>>totalSize>>byteReceived>>fileName; ? ?
? ? ? ? newFile = new QFile(fileName); ?
? ? ? ? newFile->open(QFile::WriteOnly); ?
? ? } ?
? ? else ?//正式讀取文件內(nèi)容 ?
? ? { ?
? ? ? ? inBlock = receivedSocket->readAll(); ?
??
? ? ? ? byteReceived += inBlock.size(); ?
? ? ? ? newFile->write(inBlock); ?
? ? ? ? newFile->flush(); ?
? ? } ??
? ? ui->progressLabel->show(); ?
? ? ui->receivedProgressBar->setMaximum(totalSize); ?
? ? ui->receivedProgressBar->setValue(byteReceived); ?
??
? ? if(byteReceived == totalSize) ?
? ? { ?
? ? ? ? ui->receivedStatusLabel->setText(tr("%1接收完成").arg(fileName)); ?
??
? ? ? ? inBlock.clear(); ?
? ? ? ? byteReceived = 0; ?
? ? ? ? totalSize = 0; ?
? ? } ?
} ?
??
Widget::~Widget() ?
{ ?
? ? delete ui; ?
} ??
void Widget::on_pushButton_clicked() ?
{ ?
? ? totalSize = 0; ?
? ? byteReceived = 0; ?
??
? ? server = new QTcpServer(this); ?
? ? server->listen(QHostAddress("192.168.1.137"), 1000); ?
??
? ? connect(server, SIGNAL(newConnection()), this, SLOT(acceptConnection())); ?
??
? ? ui->receivedProgressBar->setValue(0); ?
? ? ui->receivedStatusLabel->setText(tr("開始監(jiān)聽...")); ?
}?以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用C++實現(xiàn)MySQL數(shù)據(jù)庫連接池
這篇文章主要為大家詳細介紹了如何使用C++實現(xiàn)MySQL數(shù)據(jù)庫連接池,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解下2024-03-03
C++簡明圖解分析靜態(tài)成員與單例設(shè)計模式
與靜態(tài)數(shù)據(jù)成員不同,靜態(tài)成員函數(shù)的作用不是為了對象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員,靜態(tài)成員函數(shù)沒有this指針。既然它沒有指向某一對象,也就無法對一個對象中的非靜態(tài)成員進行默認訪問2022-06-06
C++實現(xiàn)LeetCode(92.倒置鏈表之二)
這篇文章主要介紹了C++實現(xiàn)LeetCode(倒置鏈表之二),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
數(shù)據(jù)結(jié)構(gòu) 棧的操作實例詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu) 順序棧的定義、初始化、空棧判斷、入棧、出棧操作的相關(guān)資料,需要的朋友可以參考下2017-06-06
解析C++編程中virtual聲明的虛函數(shù)以及單個繼承
這篇文章主要介紹了C++編程中virtual聲明的虛函數(shù)以及單個繼承,剖析虛函數(shù)和單個基類所能夠繼承的成員,要的朋友可以參考下2016-01-01

