Minio上传url资源文件,文件内容不全的问题

遇到问题

使用minio-client时候上传文件为url链接时候,上传inputstream流出现了文件上传成功,但是文件内容缺失,无法正常打开!


先看看基本的依赖和配置代码:

pom.xml依赖

java 复制代码
     <!-- tika MIME检测机制 -->
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>3.0.0-BETA2</version>
        </dependency>
        <!-- minio     -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.11</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.27</version>
        </dependency>

minio配置

java 复制代码
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
    private String accessKey;

    private String secretKey;

    private String url;

    private String bucketName;

    @Bean
    public MinioClient minioClient(){
        return MinioClient.builder()
                .region("cn-north-1")
                .endpoint(url)
                .credentials(accessKey,secretKey)
                .build();
    }

}

上传文件代码

java 复制代码
    /**
     *  url 上传
     *
     * @param urlStr        urlStr
     * @param bucketName bucket名称
     * @param fileName   文件名称
     * @return {@link String }
     */
    public String upload(String urlStr ,String bucketName, String fileName) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.connect();
            // 得到网络返回的输入流
            InputStream inputStream = conn.getInputStream();
            String contentType = new Tika().detect(inputStream);
            String extension = MimeTypes.getDefaultMimeTypes().forName(contentType).getExtension();

            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName + extension)
                    .stream(inputStream, inputStream.available(), -1)
                    .contentType(contentType)
                    .build());
            // 需要设置为public
            return fileName + extension;
        } catch (Exception e) {
            log.error("minio上传文件错误:{}", e.getMessage(), e);
            throw new RuntimeException("minio上传文件错误:" + e.getMessage(), e);
        }
    }

debug启动的问题

多次上传发现inputStream.available()的长度每次都不一样,看一下源码这个available方法返回的值是怎么个事

哦吼,问题找到了!!! 他一直在估计这个输入流的长度,就没有直接读出来,那么问题来了,我只能使用File类来获取其长度吗?

还有解法: "A subclass's implementation of this method may choose to throw an IOException if this input stream has been closed by invoking the close() method",那还是有一些子类的Stream方法能实现返回流中的字节总数 ,百度了一下,发现有FileInputStream,ByteArrayInputStream,BufferedInputStream类能完成统计流中字节数的统计!

新增处理类

java 复制代码
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

@Slf4j
public class FileUtil {

    /**
     * 通过网络地址获取文件InputStream(持续获取)
     *
     * @param urlStr 地址
     * @return inputStream
     */
    public static InputStream returnByteStream(String urlStr) {
        if (StrUtil.isEmpty(urlStr) || !urlStr.matches("^(http|https)://.*$")) {
            throw new RuntimeException("url存在问题,请检查是否可以下载!");
        }
        try {
            // 利用HttpURLConnection对象,我们可以从网络中获取网页数据.
            URL url = new URL(urlStr);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.connect();
            // 得到网络返回的输入流
            InputStream inputStream = conn.getInputStream();
            // 转化为ByteArrayInputStream
            byte[] data = stream2ByteArray(inputStream);
            return new ByteArrayInputStream(data);
        } catch (Exception e) {
            log.error("url文件下载错误!");
            throw new RuntimeException("url文件下载错误!错误原因是:" + e.getMessage(), e);
        }

    }

    /**
     * 获取流中字节数组
     *
     * @param inputStream 输入流
     * @return {@link byte[] }
     */
    public static byte[] stream2ByteArray(InputStream inputStream) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 处理大文件流
        BufferedInputStream bis = new BufferedInputStream(inputStream);
        try {
            byte[] buffer = new byte[2048];
            int len = -1;
            while ((len = bis.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            return outputStream.toByteArray();
        } catch (Exception e) {
            log.error("文件处理出现问题,{}", e.getMessage());
            throw new RuntimeException(e);
        } finally {
            try {
                outputStream.close();
                inputStream.close();
            } catch (Exception e) {
                log.error("输入输出流关闭错误,{}", e.getMessage());
            }
        }
    }
}

修改后代码

java 复制代码
   /**
     *  url 上传
     *
     * @param urlStr        urlStr
     * @param bucketName bucket名称
     * @param fileName   文件名称
     * @return {@link String }
     */
    public String upload(String urlStr ,String bucketName, String fileName) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            // 此处获取到流并且计算出长度
            InputStream inputStream = FileUtil.returnByteStream(urlStr);
            String contentType = new Tika().detect(inputStream);
            String extension = MimeTypes.getDefaultMimeTypes().forName(contentType).getExtension();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName + extension)
                     // 此处的inputStream.available()长度就是文件的长度
                    .stream(inputStream, inputStream.available(), -1)
                    .contentType(contentType)
                    .build());
            // 需要设置为public
            return fileName + extension;
        } catch (Exception e) {
            log.error("minio上传文件错误:{}", e.getMessage(), e);
            throw new RuntimeException("minio上传文件错误:" + e.getMessage(), e);
        }
    }

至此,minio上传文件后,文件可以正常打开了!

相关推荐
程序媛-徐师姐8 分钟前
Java 基于SpringBoot+vue框架的老年医疗保健网站
java·vue.js·spring boot·老年医疗保健·老年 医疗保健
yngsqq9 分钟前
c#使用高版本8.0步骤
java·前端·c#
尘浮生18 分钟前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
小白不太白95023 分钟前
设计模式之 模板方法模式
java·设计模式·模板方法模式
Tech Synapse25 分钟前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
xoxo-Rachel31 分钟前
(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
java·数据库·mysql
乌啼霜满天24933 分钟前
JDBC编程---Java
java·开发语言·sql
色空大师1 小时前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)1 小时前
设计模式-创建型-建造者模式
java·设计模式·建造者模式