如何在Qt中发送文件

How to send a file in Qt?

本文关键字:文件 Qt      更新时间:2023-10-16

我正在尝试从客户端发送文件到服务器。但它只发送文件的一部分。似乎当文件大小超过2Mb时就会发生这种情况。有什么问题吗?对不起,如果这是一个愚蠢的问题,但我在谷歌上找不到答案。

这是客户端:

#include "widget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    progressBar = new QProgressBar(this);
    tcpSocket = new QTcpSocket(this);
    fileLabel = new QLabel(this);
    progressLabel = new QLabel(this);
    fileBtn = new QPushButton(this);
    fileBtn->setText("Open");
    sendBtn = new QPushButton(this);
    sendBtn->setText("Send");
    layout = new QGridLayout;
    layout->addWidget(fileBtn, 0, 0);
    layout->addWidget(sendBtn, 0, 1);
    layout->addWidget(fileLabel, 1, 0);
    layout->addWidget(progressBar, 2, 0);
    connect(fileBtn, &QPushButton::clicked, this, &Widget::fileOpened);
    connect(sendBtn, &QPushButton::clicked, this, &Widget::onSend);
    setLayout(layout);
}
Widget::~Widget()
{
}
void Widget::fileOpened()
{
    fileName = QFileDialog::getOpenFileName(this, tr("Open file"));
    QFileInfo fileInfo(fileName);
    fileLabel->setText(fileInfo.fileName() + " : " + QString::number(fileInfo.size()));
    qDebug() << fileName;
}
void Widget::onSend()
{
    tcpSocket->connectToHost("127.0.0.1", 33333);
    QFile file(fileName);
    QDataStream out(tcpSocket);
    int size = 0;
    if (file.open(QIODevice::ReadOnly))
    {
        QFileInfo fileInfo(file);
        QString fileName(fileInfo.fileName());
        out << fileName;
        qDebug() << fileName;
        out << QString::number(fileInfo.size());
        qDebug() << fileInfo.size();
        progressBar->setMaximum(fileInfo.size());
        while (!file.atEnd())
        {
            QByteArray rawFile;
            rawFile = file.read(5000);
            //false size inc
            QFileInfo rawFileInfo(rawFile);
            size += rawFileInfo.size();
            out << rawFile;
            progressBar->setValue(rawFile.size());
            qDebug() << QString::number(fileInfo.size());
            qDebug() << "ToSend:"<< rawFile.size();
        }
        out << "#END";
    }
}

这是一个服务器文件:

#include "myserver.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    startBtn = new QPushButton(this);
    startBtn->setText("Connect");
    progressBar = new QProgressBar(this);
    layout = new QGridLayout;
    layout->addWidget(startBtn, 0, 0);
    layout->addWidget(progressBar, 1, 0);
    connect(startBtn, &QPushButton::clicked, this, &MainWindow::on_starting_clicked);
    setCentralWidget (new QWidget (this));
    centralWidget()->setLayout(layout);
}
MainWindow::~MainWindow()
{
    server_status=0;
}
void MainWindow::on_starting_clicked()
{
    startBtn->setText("Connecting...");
    tcpServer = new QTcpServer(this);
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
    if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0)
    {
        qDebug() <<  QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString());
    }
    else
    {
        server_status=1;
        qDebug() << QString::fromUtf8("Сервер запущен!");
        startBtn->setText("Running");
    }
}
void MainWindow::acceptConnection()
{
    qDebug() << QString::fromUtf8("У нас новое соединение!");
    tcpServerConnection = tcpServer->nextPendingConnection();
    connect(tcpServerConnection,SIGNAL(readyRead()),this, SLOT(slotReadClient()));
    // tcpServer->close();
    QDir::setCurrent("/Users/vlad/Desktop/");
    QString fileName;
    QString fileSize;
}

void MainWindow::slotReadClient()
{
    QDataStream in(tcpServerConnection);
    QByteArray z;
    if (!isInfoGot)
    {
        isInfoGot = true;
        in >> fileName;
        qDebug() << fileName;
        in >> fileSize;
        qDebug() << fileSize;
    }
    QFile loadedFile(fileName);
    if (loadedFile.open(QIODevice::Append))
    {
        while (tcpServerConnection->bytesAvailable())
        {
            qDebug() << "bytesAvailable:" << tcpServerConnection->bytesAvailable();
            in >> z;
            qDebug() << z;
            loadedFile.write(z);
        }
        loadedFile.close();
    }
}

到目前为止,我遇到了同样的问题。所以我找到了一个解。在大约200Mb的文件上测试,没有问题。

发送方的部分:

void FileSender::send()
{
    QTcpSocket *socket = new QTcpSocket;
    connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    // specified m_host and m_port to yours
    socket->connectToHost(m_host, m_port);
    socket->waitForConnected();
    if ( (socket->state() != QAbstractSocket::ConnectedState) || (!m_file->open(QIODevice::ReadOnly)) ) {
        qDebug() << "Socket can't connect or can't open file for transfer";
        delete socket;
        return;
    }
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_4);
    // This part i  need to send not only file, but file name too
    // Erase it if you needn't it 
    out << (quint32)0 << m_file->fileName();
    QByteArray q = m_file->readAll();
    block.append(q);
    m_file->close();
    out.device()->seek(0);
    // This difference appear because of we send file name
    out << (quint32)(block.size() - sizeof(quint32));
    qint64 x = 0;
    while (x < block.size()) {
        qint64 y = socket->write(block);
        x += y;
        //qDebug() << x;    // summary size you send, so you can check recieved and replied sizes
    }
}
服务器部分:

我指定我的服务器为:

class Server : public QTcpServer
{
    Q_OBJECT
public:
    explicit Server(QHostAddress host = QHostAddress::Any,
                    quint16 port      = Constants::Server::DEFAULT_PORT,
                    QObject *parent   = 0);
    ~Server();
public slots:
    void start();
protected:
    void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
private:
    QHostAddress m_host;
    quint16      m_port;
};

和实现:

Server::Server(QHostAddress host, quint16 port, QObject *parent)
    : QTcpServer(parent),
      m_host(host),
      m_port(port)
{
    ...
    // your settings init there
}
void Server::start()
{
    if ( this->listen(m_host, m_port) )
        qDebug() << "Server started at " << m_host.toString() << ":" << m_port;
    else
        qDebug() << "Can't start server";
}
void Server::incomingConnection(qintptr handle)
{
    qDebug() << "incomingConnection = " << handle;
    SocketThread *thread = new SocketThread(handle);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

您可以看到,我创建了一个新的类SocketThread作为我需要的多线程服务器接收。

class SocketThread : public QThread
{
    Q_OBJECT
public:
    SocketThread(qintptr descriptor, QObject *parent = 0);
    ~SocketThread();
protected:
    void run() Q_DECL_OVERRIDE;
signals:
    void onFinishRecieved();
private slots:
    void onReadyRead();
    void onDisconnected();
private:
    qintptr     m_socketDescriptor;
    QTcpSocket *m_socket;
    qint32      m_blockSize;
};

SocketThread::SocketThread(qintptr descriptor, QObject *parent)
    : QThread(parent),
      m_socketDescriptor(descriptor),
      m_blockSize(0)
{
}
SocketThread::~SocketThread()
{
    delete m_socket;
}
void SocketThread::run()
{
    m_socket = new QTcpSocket;
    m_socket->setSocketDescriptor(m_socketDescriptor);
    connect(m_socket, SIGNAL(readyRead()),    this, SLOT(onReadyRead()),    Qt::DirectConnection);
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
    exec();
}
void SocketThread::onReadyRead()
{
    QDataStream in(m_socket);
    in.setVersion(QDataStream::Qt_5_4);
    if (m_blockSize == 0) {
        if (m_socket->bytesAvailable() < sizeof(quint32))
        return;
        in >> m_blockSize;
    }
    if (m_socket->bytesAvailable() < m_blockSize)
        return;
    QString fileName;
    // get sending file name
    in >> fileName;
    QByteArray line = m_socket->readAll();
    QString filePath = "YOUR"; // your file path for receiving  
    fileName = fileName.section("/", -1);
    QFile target(filePath + "/" + fileName);
    if (!target.open(QIODevice::WriteOnly)) {
        qDebug() << "Can't open file for written";
        return;
    }
    target.write(line);
    target.close();
    emit onFinishRecieved();
    m_socket->disconnectFromHost();
}
void SocketThread::onDisconnected()
{
    m_socket->close();
    // leave event loop
    quit();
}

我希望你将能够适应我的代码到您的项目。最好的祝福

Vlad,我建议你看看Qt的例子,像这样:http://doc.qt.io/qt-5/qtbluetooth-btfiletransfer-example.html

忽略BT特定的东西,看看它能做什么。

我想我可以帮助你更多,如果我有一个独立的代码,我可以编译…也就是说,你没有发布头文件、主文件等等。拉上拉链,在某个地方拉上,等我迟交报告回来后,我可以看看是哪里出了问题!div =]

我正在寻找相同的解决方案。最后,我能够在没有QDataStream的情况下将文件传输到635MB

我只是使用下面的代码。

为客户端。

void MyClient::establishConnection(QString ip, quint16 port){
this->ip = ip;
this->port = port;
socket = new QTcpSocket();
socket->connectToHost(ip, port);
socket->waitForConnected(3000);
QFile file("D:/dummy.txt");   //file path      
file.open(QIODevice::ReadOnly);
QByteArray q = file.readAll();
socket->write(q);
}

表示服务器

void MyThread::readyRead(){

QByteArray line = socket->readAll();
QFile target;
target.setFileName("D:/new1.txt");

if (!target.open(QIODevice::WriteOnly | QIODevice::Append)) {
    qDebug() << "Can't open file for written";
    return;
}
target.write(line);
target.close();
qDebug() << "file size: " << target.size();
qDebug() << "Finished!";

}

现在,我的问题是如果我使用QDataStream会有什么效果?