您现在的位置是:首页 >学无止境 >Qt C++通过网络使用MinIO网站首页学无止境

Qt C++通过网络使用MinIO

#惊蛰# 2025-05-20 00:01:04
简介qt 如何使用minio

Qt C++在局域网下通过网络请求访问JAVA后端,从而调用MinIO上传下载和删除文件


本文是windows10上的Qt桌面应用,因为MinIO的CPP编译一直没有通过,所以本人换了一种方式来间接使用MinIO上传下载和删除文件。(本应用是在局域网内)
操作思路:首先在Java后端写好MinIO的文件上传下载和删除接口,然后在Qt端使用网络访问Java后端,从而实现文件的上传下载和删除。
本文要求要在服务器电脑上先安装好MinIO服务,并且开启服务;另外把java1.8环境配置好,后面需要把java的代码运行在此服务器电脑上。安装和配置教程可自行百度。

直接上代码

Qt代码

Qt5.12,所用模块需要添加network;
添加网络模块
MinIORW.h头文件代码片段

#include <QString>
#include <QObject>
#pragma once
class MinIORW :public QObject
{
	//这里用到了信号与槽,所以要写下面这个参数
    Q_OBJECT
public:
    MinIORW() {};

    bool insertFileToMinIO(const QString& filePath, const QString& fileNewName, const QString& IP);
    bool downloadFileFromServer(const QString& fileName, const QString& savePath, const QString& IP);
    bool DeleteFileFromMinIO(const QString& fileName, const QString& IP);
};

MinIORW.cpp文件代码片段

#include "MinIORW.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QHttpMultiPart>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QEventLoop>
#pragma execution_character_set("utf-8")	//防止中文乱码

//filePath:文件的绝对路径
//date:给文件加个前缀(可用可不用) 例如20250207_fileName.txt
//IP:MinIO服务器的地址
bool MinIORW::insertFileToMinIO(const QString& filePath, const QString& date, const QString& IP)
{
    qDebug() << __FUNCTION__;
    QNetworkAccessManager* manager = new QNetworkAccessManager(this);
    QEventLoop loop;//这个是用来阻塞主进程,等待网络请求操作完成然后返回true或false
    bool uploadSuccess = false;
    QNetworkRequest request;
    //下面是JAVA后端的接口名称,需要换成你自己的
    request.setUrl(QUrl("http://" + IP + ":8081/minioOpr/insertMinIOObject"));

    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QFile* file = new QFile(filePath);//通过文件的绝对路径,读取文件数据
    if (!file->open(QIODevice::ReadOnly)) {
        qDebug() << "Could not open the file for reading";
        return false;
    }

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name="file"; filename="" + date + "_" + QFileInfo(file->fileName()).fileName() + """));
    filePart.setBodyDevice(file);
    multiPart->append(filePart);

    QNetworkReply* reply = manager->post(request, multiPart);

	//[&]符号,表示此槽函数内可以修改uploadSuccess 的值
    QObject::connect(reply, &QNetworkReply::finished, [&]() {
        //reply->deleteLater();
        //file->deleteLater();
        //multiPart->deleteLater();

        if (reply->error() == QNetworkReply::NoError) {
            qDebug() << "File uploaded successfully:" << reply->readAll();
            uploadSuccess = true;
        }
        else {
            qDebug() << "Error:" << reply->errorString();
            uploadSuccess = false;
        }
        loop.quit();
        });
    loop.exec();//开始阻塞,等待quit()运行,即可以接着运行,不然uploadSuccess的值无法使用
    reply->deleteLater();
    file->deleteLater();
    multiPart->deleteLater();
    return uploadSuccess;
}

//根据文件名fileName来下载MinIO中的文件
//savePath:下载文件到指定的路径下,例如:C:UsersDJMDesktop20250207_test.txt
//IP:MinIO服务器的地址
bool MinIORW::downloadFileFromServer(const QString& fileName, const QString& savePath, const QString& IP)
{
    qDebug() << __FUNCTION__ << fileName << savePath;
    QNetworkAccessManager* manager = new QNetworkAccessManager(this);
    QEventLoop loop;
    bool downloadSuccess = false;

    // 构建请求URL,这里假设Java后端有一个名为/download的端点
    QUrl url("http://" + IP + ":8081/minioOpr/getMinIOObject");//?fileName+ QUrl::toPercentEncoding(fileName)
    //打包请求参数赋值
    QJsonObject json;
    json["fileName"] = fileName;
    QJsonDocument doc(json);
    QByteArray jsonData = doc.toJson(QJsonDocument::Compact);

    // 创建QNetworkRequest对象并设置URL
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); // 设置内容类型为JSON
    // 发送GET请求
    QNetworkReply* reply = manager->post(request, jsonData);
    // 连接信号和槽,处理响应
    connect(reply, &QNetworkReply::finished, [&]() {
        if (reply->error() == QNetworkReply::NoError) {
            // 读取响应数据
            QByteArray fileData = reply->readAll();

            // 将数据写入到本地文件
            QFile file(savePath);
            if (file.open(QIODevice::WriteOnly)) {
                file.write(fileData);
                file.close();
                qDebug() << "File downloaded and saved to" << savePath;
                downloadSuccess = true;
            }
            else {
                qDebug() << "Failed to open file for writing:" << savePath;
                downloadSuccess = false;
            }
        }
        else {
            qDebug() << "Error downloading file:" << reply->errorString();
            downloadSuccess = false;
        }
        loop.quit();
        // 清理
        //reply->deleteLater();
        //manager->deleteLater();
        });
    loop.exec();
    reply->deleteLater();
    manager->deleteLater();
    return downloadSuccess;
}

//根据文件名fileName来删除MinIO中的文件
//IP:MinIO服务器的地址
bool MinIORW::DeleteFileFromMinIO(const QString& fileName, const QString& IP)
{
    qDebug() << __FUNCTION__;
    QNetworkAccessManager* manager = new QNetworkAccessManager(this);
    QEventLoop loop;
    bool deleteSuccess = false;
    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QJsonObject json;
    json["fileName"] = fileName;
    QJsonDocument doc(json);
    QByteArray jsonData = doc.toJson(QJsonDocument::Compact);

    // 创建QNetworkRequest对象并设置URL
    QUrl url("http://" + IP + ":8081/minioOpr/delMinIOObject");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); // 设置内容类型为JSON
    // 发送GET请求
    QNetworkReply* reply = manager->post(request, jsonData);
    QObject::connect(reply, &QNetworkReply::finished, [&]() {
        //reply->deleteLater();
        //multiPart->deleteLater();

        if (reply->error() == QNetworkReply::NoError) {
            qDebug() << "File uploaded successfully:" << reply->readAll();
            deleteSuccess = true;
        }
        else {
            qDebug() << "Error:" << reply->errorString();
            deleteSuccess = false;
        }
        loop.quit();
        });
    loop.exec();
    reply->deleteLater();
    multiPart->deleteLater();
    return deleteSuccess;
}

Java代码

本文使用的是java1.8;8.5.16的minio;
文件树
yml文件代码

# 应用服务 WEB 访问端口
server:
  port: 8081

# Spring Boot 应用配置
spring:
  application:
    name: springboot-minio
  servlet:
    multipart:
      max-file-size: 128MB  # 单个文件的最大大小
      max-request-size: 512MB  # 整个请求的最大大小

pom文件部分依赖

            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>4.9.3</version> 
            </dependency>
            <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>8.5.16</version>
            </dependency>

MinioClient配置文件

package com.javaminio.configuration;

import io.minio.MinioClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    @Bean
    public MinioClient minioClient(){
        //链式编程,构建MinIOClient对象
        return MinioClient.builder().endpoint("http://127.0.0.1:9000/")
                .credentials("admin","jszx123!")
                .build();
    }
}

controller层代码

package com.javaminio.controller;

import com.javaminio.result.R;
import com.javaminio.service.MinIORWService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;

@RestController
@CrossOrigin
@RequestMapping("/minioOpr")
public class MinIORWController {

    @Resource
    private MinIORWService minIORWService;

    @GetMapping(value="/getMinIOObjList")
    public R getMinIOObjList(){
        return R.OK(minIORWService.getObjects());
    }

    //插入
    @PostMapping(value="/insertMinIOObject")
    public R insertMinIOObject(MultipartFile file) throws Exception {
        return R.OK(minIORWService.insertData(file));
    }

    //获取文件
    @PostMapping(value="/getMinIOObject")
    public void getMinIOObject(@RequestBody Map<String,Object> map, HttpServletResponse response) throws Exception {
        try {
            String fileName = map.get("fileName").toString();
            if(fileName.isEmpty()){
                return;
            }
            // 从MinIO获取文件(这里省略了具体的bucket名称和获取文件的逻辑)
            // 假设你有一个方法可以从MinIO下载文件并返回其内容的字节数组
            byte[] fileBytes = minIORWService.getObject(fileName);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + fileName + """);
            headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setContentLength(fileBytes.length);
            response.getOutputStream().write(fileBytes);

        } catch (Exception e) {
            throw e;
        }
    }

    //删除文件
    @PostMapping(value="/delMinIOObject")
    public R delMinIOObject(@RequestBody Map<String,Object> map) throws Exception {
        String fileName = map.get("fileName").toString();
        if(Objects.equals(fileName, "") || fileName==null){
            return R.fail();
        }
        return R.OK(minIORWService.deleteObject(fileName));
    }
}

R文件代码

package com.javaminio.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class R {
    private int code;

    private String msg;

    private Object data;

    public static R OK(){
        return new R(200,"成功",null);
    }

    public static R OK(Object data){
        return new R(200,"成功",data);
    }

    public static R fail(){
        return new R(500,"失败",null);
    }

}

service层代码

package com.javaminio.service;

import io.minio.StatObjectResponse;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;


public interface MinIORWService {
    List<String> getObjects();

    boolean insertData(MultipartFile file)throws Exception;

    StatObjectResponse getObjStat(String fileName) throws Exception;
    byte[] getObject(String fileName) throws Exception;

    boolean deleteObject(String fileName) throws Exception;
}

serviceImpl层代码

package com.javaminio.service.impl;

import com.javaminio.service.MinIORWService;
import io.minio.*;
import io.minio.messages.Item;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

@Service
public class MinIORWServiceImpl implements MinIORWService {
    @Resource
    private MinioClient minioClient;

    public List<String> getObjects(){
//        Iterable<Result<Item>> listObjects = minioClient.listObjects(ListObjectsArgs.builder()
//                .bucket("jszx").build());
//        List<String> list = new ArrayList<>();
//        listObjects.forEach(itemResult -> {
//            try {
//                Item item = itemResult.get();
//                System.out.println(item.objectName());
//                list.add(item.objectName());
//            }catch (Exception e){
//                throw new RuntimeException();
//            }
//        });
//        return list;
        // 用于存储文件名的列表
        List<String> objectNames = new ArrayList<>();

        try {
            // 列出存储桶中的所有对象
            Iterable<Result<Item>> objects = minioClient.listObjects(ListObjectsArgs.builder().bucket("jszx").build());

            // 遍历结果并添加文件名到列表中
            for (Result<Item> result : objects) {
                Item item = result.get();
                objectNames.add(item.objectName());
                System.out.println("File name: " + item.objectName());
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 根据需要处理异常,例如记录日志或抛出运行时异常
            throw new RuntimeException("Error occurred while listing objects in bucket jszx", e);
        }

        return objectNames;
    }
    public boolean insertData(MultipartFile file) throws Exception{
        try {
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket("jszx").build());
            if(!isExist){
                minioClient.makeBucket(MakeBucketArgs.builder().bucket("jszx").build());//创建桶
            }
            // 将MultipartFile转换为InputStream
            InputStream inputStream = file.getInputStream();
            String objectName = file.getOriginalFilename(); // 可以根据需要修改对象名称
            //放文件
            ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs
                    .builder()
                    .bucket("jszx").object(objectName)
                    .stream(inputStream, file.getSize(), -1)
                    .build());
            System.out.println(objectWriteResponse);
            return true;
        }catch (Exception e){
            throw e;
        }
    }

    public byte[] getObject(String fileName) throws Exception{
        GetObjectResponse getObjectResponse  = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket("jszx")
                        .object(fileName)
                        .build());

        // 将文件内容读取到byte数组中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = getObjectResponse.read(buffer)) != -1) {
            baos.write(buffer, 0, bytesRead);
        }
        return baos.toByteArray();
    }

    public StatObjectResponse getObjStat(String fileName) throws Exception{
        return minioClient.statObject(StatObjectArgs
                .builder()
                .bucket("jszx")
                .object(fileName)
                .build());
    }

    public boolean deleteObject(String fileNames) throws Exception{
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket("jszx").build());
        if(!isExist){
            return false;
        }
        String[] fileName = fileNames.split(",");
        for(int i=0;i< fileName.length;i++){
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket("jszx").object(fileName[i]).build());
        }
        return true;
    }
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。