遇到问题
使用minio-client时候上传文件为url链接时候,上传inputstream流出现了文件上传成功,但是文件内容缺失,无法正常打开!
先看看基本的依赖和配置代码:
pom.xml依赖
<!-- 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配置
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;@Beanpublic MinioClient minioClient(){return MinioClient.builder().region("cn-north-1").endpoint(url).credentials(accessKey,secretKey).build();}}
上传文件代码
/*** 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());// 需要设置为publicreturn 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类能完成统计流中字节数的统计!
新增处理类
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();// 转化为ByteArrayInputStreambyte[] 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());}}}
}
修改后代码
/*** 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());// 需要设置为publicreturn fileName + extension;} catch (Exception e) {log.error("minio上传文件错误:{}", e.getMessage(), e);throw new RuntimeException("minio上传文件错误:" + e.getMessage(), e);}}
至此,minio上传文件后,文件可以正常打开了!