qt文件断点续传+nodejs搭建本地服务器


用nodjs来搭建一个本地的服务器,用qt编写程序实现文件的上传和断点续传的功能

nodejs服务器搭建

先去安装一个nodejs,然后在文件夹中npm init -y初始化nodejs项目,npm install express multer安装所需要的包,在项目目录创建一个server.js文件,并添加下面的代码,最后用node server.js启动服务器,速成参考Node.js 教程 | 菜鸟教程 (runoob.com)

const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const port = 3000;

// 提供静态文件服务
app.use(express.static('uploads'));

// 处理文件上传的 PUT 请求
app.put('/upload', (req, res) => {
    // 获取文件名和扩展名
    const originalFileName = req.headers['x-filename'];

    const filePath = path.join(__dirname, 'uploads', originalFileName);

    const range = req.headers['range'];
    let start = 0;

    // 处理断点续传
    if (range) {
        const parts = range.replace(/bytes=/, "").split("-");
        start = parseInt(parts[0], 10);
    }

    // 创建文件写入流,从指定位置开始写入
    const uploadStream = fs.createWriteStream(filePath, { flags: 'a', start });

    // 处理文件上传数据
    req.on('data', chunk => {
        uploadStream.write(chunk);
    });

    // 处理上传完成
    req.on('end', () => {
        uploadStream.end();
        res.end(`File uploaded successfully as ${originalFileName}`);
        console.log(`File uploaded successfully as ${originalFileName}`);
    });

    // 处理上传中断
    req.on('aborted', () => {
        uploadStream.end();
        console.log('Upload aborted.');
    });

    // 处理上传错误
    req.on('error', err => {
        uploadStream.end();
        console.error('Upload error:', err);
    });
});

// 启动服务器
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

qt代码

  • fileuploader.h
#ifndef FILEUPLOADER_H
#define FILEUPLOADER_H

#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QObject>
#include <QProgressBar>
#include <QPushButton>
#include <QUrl>
#include <QVBoxLayout>

    class FileUploader : public QWidget
{
    Q_OBJECT
public:
    explicit FileUploader(QWidget *parent = nullptr);
    ~FileUploader();

signals:

private slots:
    void selectFile();
    void startUpload();
    void pauseUpload();
    void handleUploadProgress(qint64 bytesSent, qint64 BytesTotal);
    void handleUploadFinished();

public:
    QVBoxLayout *layout;   //定义垂直布局
    QHBoxLayout *hLayout1; //定义水平布局
    QHBoxLayout *hLayout2;
    QPushButton *selectButton;
    QPushButton *startButton;
    QPushButton *pauseButton;
    QLineEdit *filePathEdit;
    QProgressBar *progressBar;
    QWidget *centralWidget;

private:
    QNetworkAccessManager *manager;
    QNetworkReply *reply;
    QFile *file;
    QString selectedFilePath;
    qint64 uploadBytes; //记录已上传字节数
    bool isPaused;      //是否已暂停
};

#endif // FILEUPLOADER_H
  • fileuploader.cpp
#include "fileuploader.h"

FileUploader::FileUploader(QWidget *parent)
    : QWidget{parent}
{
    //窗口初始化
    layout = new QVBoxLayout();
    hLayout1 = new QHBoxLayout();
    hLayout2 = new QHBoxLayout();

    selectButton = new QPushButton("选择文件", this);
    startButton = new QPushButton("开始传输", this);
    pauseButton = new QPushButton("暂停传输", this);
    filePathEdit = new QLineEdit(this);
    progressBar = new QProgressBar(this);
    // progressBar->setRange(0, 100);
    // progressBar->setValue(0);

    hLayout1->addWidget(selectButton);
    hLayout1->addWidget(filePathEdit);
    hLayout1->addWidget(startButton);
    layout->addLayout(hLayout1);

    hLayout2->addWidget(progressBar);
    hLayout2->addWidget(pauseButton);
    layout->addLayout(hLayout2);

    centralWidget = new QWidget(this);
    centralWidget->setLayout(layout);
    //网络请求部分初始化
    manager = new QNetworkAccessManager(this);
    reply = nullptr;
    file = nullptr;
    uploadBytes = 0;
    isPaused = false;
    //信号槽注册
    connect(selectButton, &QPushButton::clicked, this, &FileUploader::selectFile);
    connect(startButton, &QPushButton::clicked, this, &FileUploader::startUpload);
    connect(pauseButton, &QPushButton::clicked, this, &FileUploader::pauseUpload);
}

FileUploader::~FileUploader()
{
    reply->deleteLater();
    file->close();
    file->deleteLater();
    file = nullptr;
}

void FileUploader::selectFile()
{
    selectedFilePath = QFileDialog::getOpenFileName(this, "选择一个文件");
    if (!selectedFilePath.isEmpty()) {
        filePathEdit->setText(selectedFilePath);
    }
}
//槽函数,处理开始上传按钮
void FileUploader::startUpload()
{
    if (selectedFilePath.isNull()) {
        qDebug() << "没有选择文件";
    }

    QUrl url("http://localhost:3000/upload");
    QNetworkRequest request(url);
    //设置头部字段,application/octet-stream是一个通用的二进制数据类型
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
    //提取文件名并转为utf8编码的字节数组,作为http头部字段x-filename的值
    request.setRawHeader("x-filename", QFileInfo(selectedFilePath).fileName().toUtf8());

    file = new QFile(selectedFilePath);
    if (!file->open(QIODevice::ReadOnly)) {
        qDebug() << "文件打开错误";
        return;
    }
    qDebug() << "...........................";
    //如果文件尚未打开或已经关闭,重新打开
    if (file == nullptr || !file->isOpen()) {
        file = new QFile(selectedFilePath);
        if (!file->open(QIODevice::ReadOnly)) {
            qDebug() << "文件打开错误";
            return;
        }
    }

    if (uploadBytes > 0) {
        request.setRawHeader("Range", QByteArray("bytes=") + QByteArray::number(uploadBytes) + "-");
        file->seek(uploadBytes);
    }
    //发送put请求
    reply = manager->put(request, file);

    connect(reply, &QNetworkReply::uploadProgress, this, &FileUploader::handleUploadProgress);
    connect(reply, &QNetworkReply::finished, this, &FileUploader::handleUploadFinished);
}

//槽函数,处理暂停按钮
void FileUploader::pauseUpload()
{
    if (reply && reply->isRunning()) {
        reply->abort();
        isPaused = true;
        pauseButton->setText("继续");
        qDebug() << uploadBytes;
    } else if (isPaused) {
        isPaused = false;
        startUpload(); //继续上传
        pauseButton->setText("暂停");
    }
}

//槽函数,处理上传进度
void FileUploader::handleUploadProgress(qint64 bytesSent, qint64 BytesTotal)
{
    uploadBytes += bytesSent;
    progressBar->setMaximum(BytesTotal);
    progressBar->setValue(uploadBytes);
}

//槽函数,传输完成
void FileUploader::handleUploadFinished()
{
    if (reply->error() == QNetworkReply::NoError) {
        qDebug() << "上传成功";
        QMessageBox::information(this, "提示", "上传成功");
        uploadBytes = 0;
    } else {
        qDebug() << "上传失败" << reply->errorString();
    }
}

  • mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    uploader = new FileUploader(this);
    //初始化窗口界面
    setCentralWidget(uploader->centralWidget);
}

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

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Node.js搭建本地服务器非常简单。首先,我们需要安装Node.js。 安装完成后,打开终端(或命令行窗口),进入想要搭建服务器文件夹。 创建一个新的Node.js文件,命名为server.js(或其他任何你喜欢的名称),然后将以下代码复制到该文件中: ```javascript const http = require('http'); const fs = require('fs'); const path = require('path'); const server = http.createServer((req, res) => { let filePath = path.join(__dirname, req.url); let contentType = 'text/html'; fs.exists(filePath, (exists) => { if (exists) { fs.readFile(filePath, (error, content) => { if (error) { res.writeHead(500); res.end('Server Error'); } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } }); } else { res.writeHead(404); res.end('File Not Found'); } }); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000/'); }); ``` 上述代码使用了Node.js的HTTP、FS和Path模块。server.js文件创建了一个HTTP服务器。当有请求发送到服务器时,它会检查请求的URL地址是否是文件路径,并将请求的文件作为响应发回给客户端。 在终端中运行以下命令启动服务器: ``` node server.js ``` 这将在本地启动一个HTTP服务器,监听在3000端口上。你可以通过浏览器访问http://localhost:3000/ 来访问该服务器。 请注意,在代码中,`contentType`变量默认设置为'text/html',这意味着服务器会将所有请求的文件作为HTML文件返回。你也可以根据需要更改它,例如如果你想返回CSS文件,可以将其设置为'text/css'。 以上就是使用Node.js搭建本地服务器并访问文件的简单过程。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值