首頁 > 軟體

QT實現檔案傳輸功能

2022-08-18 22:02:10

本文範例為大家分享了QT實現檔案傳輸功能的具體程式碼,供大家參考,具體內容如下

過程如下:

1、伺服器端設定監聽通訊端,開始監聽;

2、使用者端在連線成功時開始傳送檔案,有connected()訊號連線send()槽,send()傳送檔案頭資訊,包括檔名、檔案總大小和檔名大小等;

3、傳送完檔案頭資訊時開始傳送檔案內容,有bytesWritten(qint64)訊號連線到goOnSend(qint64)槽,前者是當想通訊端寫入資料時會出發的訊號,即當已經想通訊端寫入資料,就繼續傳送資料,有send()傳送檔案頭資訊開始觸發,直到檔案傳完為止。

4、在伺服器端,首先接收檔案頭資訊,然後讀取檔名來用新建檔案的方式開啟一個檔案,然後讀取檔名即檔案等大小資訊,用來更新進度條和繼續接收資料;

5、實現迴圈傳輸,在使用者端,因為第一次send()是由connected()訊號觸發的,之後的每次傳送應該手動呼叫send();在伺服器端,在有新資料到達時,會判斷是否為標頭檔案,因此在每次檔案傳完的時候將byteReceived重置為0,即下一次再接收到資料的時候依據byteReceived判斷的結果就是一個新檔案了。

使用者端程式碼:

#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;  //每次傳送資料的大小  
    qint64 byteToWrite;  //剩餘資料大小  
    qint64 totalSize;  //檔案總大小  
  
    int sendTimes;  //用來標記是否為第一次傳送,第一次以後連線訊號觸發,後面的則手動呼叫  
  
private slots:  
    void send();  //傳送檔案頭資訊  
    void goOnSend(qint64);  //傳送檔案內容  
    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()  //傳送檔案頭資訊  
{  
    byteToWrite = localFile->size();  //剩餘資料的大小  
    totalSize = localFile->size();  
  
    loadSize = 4*1024;  //每次傳送資料的大小  
  
    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);  //回到位元組流起點來寫好前面連個qint64,分別為總大小和檔名等資訊大小  
    out<<totalSize<<qint64(outBlock.size());  
  
    tcpClient->write(outBlock);  //將讀到的檔案傳送到通訊端  
  
    ui->progressLabel->show();  
    ui->sendProgressBar->setMaximum(totalSize);  
    ui->sendProgressBar->setValue(totalSize - byteToWrite);  
}  
  
void Widget::goOnSend(qint64 numBytes)  //開始傳送檔案內容  
{  
    byteToWrite -= numBytes;  //剩餘資料大小  
    outBlock = localFile->read(qMin(byteToWrite, loadSize));  
    tcpClient->write(outBlock);  
  
    ui->sendProgressBar->setMaximum(totalSize);  
    ui->sendProgressBar->setValue(totalSize - byteToWrite);  
  
    if(byteToWrite == 0)  //傳送完畢  
        ui->sendStatusLabel->setText(tr("檔案傳送完畢!"));  
}  
  
Widget::~Widget()  
{  
    delete ui;  
}  
  
void Widget::on_openPushButton_clicked()  //開啟檔案並獲取檔名(包括路徑)  
{  
    ui->sendStatusLabel->setText(tr("正在開啟檔案..."));  
    ui->sendProgressBar->setValue(0);  //非第一次傳送  
  
    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)  //只有第一次傳送的時候,是發生在連線產生訊號connect時  
    {  
        tcpClient->connectToHost(QHostAddress("192.168.1.137"), 1000);  
        sendTimes = 1;    
    }  
    else  
        send();  //第一次傳送的時候是由connectToHost出發connect訊號才能呼叫send,第二次之後就需要呼叫send了  
  
    ui->sendStatusLabel->setText(tr("正在傳送檔案 %1").arg(fileName));  
}  

伺服器端程式碼:

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;  //總共需要傳送的檔案大小(檔案內容&檔名資訊)  
    qint64 byteReceived;  //已經傳送的大小  
  
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)  //才剛開始接收資料,此資料為檔案資訊  
    {  
        ui->receivedProgressBar->setValue(0);  
  
        QDataStream in(receivedSocket);  
        in>>totalSize>>byteReceived>>fileName;    
        newFile = new QFile(fileName);  
        newFile->open(QFile::WriteOnly);  
    }  
    else  //正式讀取檔案內容  
    {  
        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("開始監聽..."));  
} 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com