当前位置: 首页 > article >正文

byte[]/InputStream/MultipartFile之间进行转换

前言

问题产生:

最近开发项目的时候,遇到了文件上传对象转换的问题 -> 我在对接抖音开放平台的时候,有一个图片上传的接口,需要将byte[]转为MultipartFile 对象,但是发现根本没有这样的工具类,后面翻阅了不少帖子得到了解决方案。


需求是这样的:

阿里云的OSS对象存储照片URL需要通过Java获取到图片流,不过我这里下载的是byte数组,byte数组与流对象之间的转换还是比较简单的,这里我就是希望 byte 数组转为MultipartFile对象:

获取图片的字节数据:

// 图片的链接
String url = "https://profile-avatar.csdnimg.cn/6337cc80d5124929b02f7a57c790083a_qq_31762741.jpg"; 
// 下载图片为字节数组
byte[] bytes = HttpUtil.downloadBytes(url);

然后再将图片流上传到抖音的服务器,但是抖音的上传图片接口长这样:

上传对象是 MultipartFile,而我的图片资源又是 byte 数组,这之间就需要做一个转换了。


说明

教程中大量使用到了Hutool工具:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.11</version>
</dependency>

byte[]转MultipartFile

在将byte[]转换为MultipartFile时,可以通过以下步骤完成:

  1. 导入相关依赖:确保项目中引入了Spring框架的相关依赖,以及文件上传所需的其他依赖。
  2. 创建一个实现了MultipartFile接口的自定义类:由于MultipartFile是一个接口,无法直接实例化,因此需要创建一个自定义类来实现该接口。
  3. 实现自定义类的相关方法:自定义类需要实现MultipartFile接口中的方法,包括getName()getOriginalFilename()getContentType()getSize()getInputStream()等方法。其中,getInputStream()方法需要将byte[]转换为InputStream

以下是一个示例代码,展示了如何将byte[]转换为MultipartFile

package com.hsqyz.common.utils.file;

import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;

/**
 * 实现将字节数组转换为 MultipartFile 的工具类。
 *
 * @author 花伤情犹在
 */
public class ByteToMultipartFile implements MultipartFile, Serializable {

    private final byte[] content; // 存储字节数组的内容
    private final String name; // MultipartFile 的名称
    private final String originalFilename; // 原始文件名
    private final String contentType; // 文件的内容类型

    /**
     * 构造函数,初始化 MultipartFile 对象。
     *
     * @param content          字节数组内容
     * @param name             MultipartFile 的名称
     * @param originalFilename 原始文件名
     * @param contentType      文件的内容类型
     */
    public ByteToMultipartFile(byte[] content, String name, String originalFilename, String contentType) {
        this.content = content;
        this.name = name;
        this.originalFilename = originalFilename;
        this.contentType = contentType;
    }

    /**
     * 获取 MultipartFile 的名称。
     *
     * @return MultipartFile 的名称
     */
    @Override
    public String getName() {
        return name;
    }

    /**
     * 获取原始文件名。
     *
     * @return 原始文件名
     */
    @Override
    public String getOriginalFilename() {
        return originalFilename;
    }

    /**
     * 获取文件的内容类型。
     *
     * @return 文件的内容类型
     */
    @Override
    public String getContentType() {
        return contentType;
    }

    /**
     * 判断 MultipartFile 是否为空。
     *
     * @return 如果字节数组长度为 0,则返回 true;否则返回 false
     */
    @Override
    public boolean isEmpty() {
        return this.content.length == 0;
    }

    /**
     * 获取文件的大小(字节数)。
     *
     * @return 文件的大小
     */
    @Override
    public long getSize() {
        return this.content.length;
    }

    /**
     * 获取字节数组内容。
     *
     * @return 字节数组内容
     * @throws IOException 如果发生 I/O 错误
     */
    @Override
    public byte[] getBytes() throws IOException {
        return this.content;
    }

    /**
     * 获取输入流。
     *
     * @return 输入流
     * @throws IOException 如果发生 I/O 错误
     */
    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(this.content);
    }

    /**
     * 将文件内容保存到指定位置。
     *
     * @param dest 目标文件路径
     * @throws IOException           如果发生 I/O 错误
     * @throws IllegalStateException 如果文件状态不正确
     */
    @Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        // 实现文件的保存操作,可根据具体需求自行实现
        // 例如:Files.write(dest.toPath(), content);
        Files.write(dest.toPath(), content);
    }

}

使用该自定义类时,可以通过以下方式将byte[]转换为MultipartFile

byte[] fileBytes = // 从某处获取到的byte[]数据
String name = // 表单字段的名称
String fileName = // 文件名
String contentType = // 文件类型

// 转换数据
MultipartFile multipartFile = new ByteToMultipartFile(fileBytes, "file", fileName, contentType);

可以看到这里仍然还需要一些数据,这里声明出来:

变量说明
fileBytes这个字节数据就是我们通过 Hutool 的下载工具已经拿到了【HttpUtil.downloadBytes(url)】
name这个字段名称对应接口的表单字段名
fileName文件名字可以选择截取 oss 图片 url 路径上的文件名
contentType响应内容类型也是可以通过响应头拿到的

fileBytes:

这里直接使用 Hutool 的请求下载工具来获取 urlbyte 字节数据 。

// 图片的链接
String url = "https://profile-avatar.csdnimg.cn/6337cc80d5124929b02f7a57c790083a_qq_31762741.jpg"; 
// 下载图片为字节数组
byte[] bytes = HttpUtil.downloadBytes(url);

name:

例如抖音上传图片接口的二进制图片字段名为 Image,那我们这里也写死为 Image 即可。


fileName:

我们的 oss 图片对象通常都是文件名跟随在 url 路径后面的,例如阿里云 oss:

我们可以通过截取 url 里面最后一个/反斜杠的方式获取文件名,可以看到我们下载下来的文件名字就是最后一个/反斜杠后面的内容:

这里封装了一个截取的 url 最后一个/反斜杠后面内容的工具类:

import cn.hutool.core.util.URLUtil;

/**
 * 文件名工具类
 *
 * @author 花伤情犹在
 */
public class FileNameUtils {

    /**
     * 从 URL 中获取文件名。
     *
     * @param url 资源的 URL
     * @return 文件名字符串,如果获取失败返回 null
     */
    public static String getFileNameFromUrl(String url) {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("URL 不能为空");
        }

        try {
            // 解析 URL
            java.net.URL parsedUrl = URLUtil.url(url);

            // 获取路径部分
            String path = parsedUrl.getPath();

            // 提取文件名
            int lastSlashIndex = path.lastIndexOf('/');
            if (lastSlashIndex >= 0 && lastSlashIndex < path.length() - 1) {
                return path.substring(lastSlashIndex + 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        // 示例 URL
        String imageUrl = "https://example.com/path/to/image.jpg"; // 替换为你实际的图片 URL

        // 获取文件名
        String fileName = FileNameUtils.getFileNameFromUrl(imageUrl);

        if (fileName != null) {
            System.out.println("文件名: " + fileName);
        } else {
            System.out.println("无法获取文件名");
        }
    }

}

contentType:

这里封转了一个工具类发起请求可以直接进行从响应头里面获取响应内容类型:

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;

/**
 * 获取 URL 资源的 ContentType。
 *
 * @author 花伤情犹在
 */
public class ContentTypeUtils {

    /**
     * 获取 URL 资源的 ContentType。
     *
     * @param url 资源的 URL
     * @return ContentType 字符串,如果获取失败返回 null
     */
    public static String getContentTypeFromUrl(String url) {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("URL 不能为空");
        }

        try {
            // 发送 HEAD 请求以获取响应头信息
            HttpResponse response = HttpUtil.createRequest(Method.GET, url).execute();

            // 检查响应状态码是否为 200
            if (response.getStatus() == 200) {
                // 从响应头中获取 ContentType
                return response.header("Content-Type");
            } else {
                System.err.println("无法获取资源,状态码: " + response.getStatus());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {
        // 示例 URL
        String imageUrl = "https://xx.com?test.jpg"; // 替换为你实际的图片 URL

        // 获取 ContentType
        String contentType = ContentTypeUtils.getContentTypeFromUrl(imageUrl);

        if (contentType != null) {
            System.out.println("Content-Type: " + contentType);
        } else {
            System.out.println("无法获取 Content-Type");
        }
    }

}

当然这里还封装了一个MultipartFile 转换工具类,不需要手动实现 MultipartFile 接口来自己造实现类:

注意需要依赖:commons-fileupload

<!-- 文件上传 -->
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.5</version>
	<scope>compile</scope>
</dependency>

工具代码如下:

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * MultipartFile 转换工具类
 *
 * @author 花伤情犹在
 */
public class MultipartFileConverter {

    /**
     * 将 byte[] 转换为 MultipartFile。
     *
     * @param bytes       文件内容的字节数组
     * @param fieldName   表单字段的名称
     * @param fileName    文件名
     * @param contentType 内容类型
     * @return 转换后的 MultipartFile 对象
     * @throws IOException 如果转换过程中发生 I/O 错误
     */
    public static MultipartFile convertByteToMultipartFile(byte[] bytes, String fieldName, String fileName, String contentType) throws IOException {
        if (bytes == null || bytes.length == 0) {
            throw new IllegalArgumentException("输入的字节数组不能为空");
        }
        FileItem item;
        try {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            item = factory.createItem(fieldName, contentType, false, fileName);

            try (ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
                 OutputStream os = item.getOutputStream()) {
                bos.write(bytes);
                os.write(bos.toByteArray());
            }
            return new CommonsMultipartFile(item);
        } catch (IOException e) {
            throw new IOException("转换 byte[] 为 MultipartFile 时发生错误", e);
        }
    }

    /**
     * 从 URL 获取图片并转换为 MultipartFile。
     *
     * @param imageUrl    图片的 URL
     * @param fileName    文件名
     * @param contentType 内容类型
     * @return 转换后的 MultipartFile 对象
     * @throws IOException 如果下载或转换过程中发生 I/O 错误
     */
    public static MultipartFile convertUrlToMultipartFile(String fieldName, String imageUrl, String fileName, String contentType) throws IOException {
        if (StrUtil.isBlank(imageUrl)) {
            throw new IllegalArgumentException("URL 不能为空");
        }
        // 从 URL 下载图片
        byte[] bytes = HttpUtil.downloadBytes(imageUrl);

        return convertByteToMultipartFile(bytes, fieldName, fileName, contentType);
    }

}

使用示例:

// 创建一个空byte 数组
byte[] bytes = new byte[1024];
// 示例 MultipartFile 对象
MultipartFile file = MultipartFileConverter.convertByteToMultipartFile(bytes, "image", "ok.jpg", "image/jpg");

MultipartFile转byte[]

MultipartFile file =  // 你的 MultipartFile 对象
// 直接获取 byte 数组
byte[] bytes = file.getBytes();

byte[]转InputStream

// 创建一个空byte 数组
byte[] bytes = new byte[1024];
ByteArrayInputStream bis = new ByteArrayInputStream(body);

InputStream转byte[]

// 使用 Hutool 的 IoUtil 读取 InputStream 并转换为 byte[]
byte[] bytes = IoUtil.readBytes(inputStream);

InputStream转MultipartFile

将 InputStream 转换为 byte[],然后请依照上面的教程 byte[]转MultipartFile 即可

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = byteArrayOutputStream.toByteArray();

MultipartFile转InputStream

MultipartFile file =  // 你的 MultipartFile 对象
InputStream inputStream = file.getInputStream();

教程结束!

教程基本都来自己互联网各大博客帖子,此篇仅作记录方便日后使用!

参考资料

参考如下:

  • 将byte[]转换为MultipartFile
  • byte[]转MultipartFile、byte[]转File一次看个够 【 推荐!!!】
  • byte[]转换InputStream/MultipartFile

http://www.kler.cn/news/342335.html

相关文章:

  • Redis 高可用方案
  • 《Electron 基础知识》设置 Vue 中引用的文件路径别名
  • 便民医疗服务小程序后端springboot 服务 vue3 开发的后端 系统设计与实现
  • springmvc直接访问 上下文路径 302 后路径更改并跳转源码解析
  • 【系统架构设计师】案例专题三:数据库系统考点梳理
  • 图像分割恢复方法
  • AI智能体:共塑企业变革新纪元,引领未来无限潜能
  • Hessian 序列化
  • Java面试题——第十篇
  • Midjourney中文版:解锁你的创意之旅
  • [红队apt]CHM电子书攻击/电子教程攻击
  • 微软确认Word离奇Bug 命名不当会导致文件被删
  • 塔吊识别数据集 yolo格式 共5076张图片 已划分好训练验证 txt格式 yolo可直接使用
  • VAS1800Q奇力科技线性芯片电荷泵热处理
  • set有哪些实现类?
  • 洗衣店管理革命:Spring Boot订单系统
  • 最新Prompt预设词指令教程大全ChatGPT、AI智能体(300+预设词应用)
  • 现货黄金价格走势图策略分析 先看“势”
  • 鸿蒙NEXT开发-页面路由(基于最新api12稳定版)
  • Excel中使用SQL语句的四种方法