最近公司做疫情通行这块,设备要求图片传base64字符串,就分享下这个工具类,以及里面的一些坑吧,直接上码。
package com.xiaotian.bus.util; import com.easylinkin.bm.thirdapi.request.upload.UploadRequest; import com.easylinkin.bm.thirdapi.response.ResponseData; import com.easylinkin.bm.thirdapi.util.ThirdPartyServeUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.io.IOUtils; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * base64文件工具类 * @author zwsky */ @Slf4j public class FileBase64Util { /** * 本地文件(图片、excel等)转换成Base64字符串 * * @param imgPath */ public static String convertFileToBase64(String imgPath) { byte[] data = null; // 读取图片字节数组 try { InputStream in = new FileInputStream(imgPath); log.info("文件大小(字节)="+in.available()); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } // 对字节数组进行Base64编码,得到Base64编码的字符串 BASE64Encoder encoder = new BASE64Encoder(); String base64Str = encoder.encode(data).replaceAll("[\\s*\t\n\r]", ""); Integer base64Len = base64Str.length(); log.info("----base64 length:{}",base64Len); return base64Str; } /** * 网络地址文件转为base64字符串相关信息 * @param netUrl 网络地址 * @return map对象 * @throws Exception */ public static Map<String,String> netUrlToBase64(String netUrl) throws Exception { Map<String,String> mp = null; URL url = new URL(netUrl); //将图片文件转化为字节数组字符串,并对其进行Base64编码处理 log.info("图片的路径为:" + url.toString()); String fileType = netUrl.substring(netUrl.lastIndexOf(".")); //打开链接 HttpURLConnection conn = null; try { conn = (HttpURLConnection) url.openConnection(); //设置请求方式为"GET" conn.setRequestMethod("GET"); //超时响应时间为5秒 conn.setConnectTimeout(5 * 1000); //通过输入流获取图片数据 InputStream inStream = conn.getInputStream(); //得到图片的二进制数据,以二进制封装得到数据,具有通用性 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); //创建一个Buffer字符串 byte[] buffer = new byte[1024]; //每次读取的字符串长度,如果为-1,代表全部读取完毕 int len = 0; //使用一个输入流从buffer里把数据读取出来 while ((len = inStream.read(buffer)) != -1) { //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 outStream.write(buffer, 0, len); } int size1 = inStream.available(); //关闭输入流 inStream.close(); byte[] data = outStream.toByteArray(); Long size = Long.parseLong(String.valueOf(outStream.size())); log.info("--outSize:{}----inSize:{}",size,size1); //对字节数组Base64编码 BASE64Encoder encoder = new BASE64Encoder(); //根据RFC822规定,BASE64Encoder编码每76个字符,还需要加上一个回车换行 //部分Base64编码的java库还按照这个标准实行 String base64 = encoder.encode(data).replaceAll("[\\s*\t\n\r]", ""); log.info("网络文件[{}]编码成base64字符串:[{}]"+url.toString()+base64); //Integer base64Len = base64.length(); //1.获取base64字符串长度(不含data:audio/wav;base64,文件头) Integer base64Len = base64.length(); /* //2.获取字符串的尾巴的最后10个字符,用于判断尾巴是否有等号,正常生成的base64文件'等号'不会超过4个 String tail = base64.substring(base64Len - 10); //3.找到等号,把等号也去掉,(等号其实是空的意思,不能算在文件大小里面) int equalIndex = tail.indexOf("="); if(equalIndex > 0) { base64Len = base64Len - (10 - equalIndex); } Integer base64Len = base64.length(); int fileSize = base64Len-(base64Len/8)*2; log.info("----base64 length:{}",base64Len); //1.获取base64字符串长度(不含data:audio/wav;base64,文件头) int size0 = base64.length(); //2.获取字符串的尾巴的最后10个字符,用于判断尾巴是否有等号,正常生成的base64文件'等号'不会超过4个 String tail = base64.substring(size0-10); //3.找到等号,把等号也去掉,(等号其实是空的意思,不能算在文件大小里面) int equalIndex = tail.indexOf("="); if(equalIndex > 0) { size0 = size0 - (10 - equalIndex); } //4.计算后得到的文件流大小,单位为字节 fileSize = (int) Math.round((size0 -( (double)size0 / 8 ) * 2)); */ //返回Base64编码过的字节数组字符串 mp = new HashMap<>(3); mp.put("fileType",fileType); mp.put("base64",base64); mp.put("size",String.valueOf(base64Len)); //mp.put("size",String.valueOf(fileSize)); } catch (IOException e) { e.printStackTrace(); throw new Exception("图片上传失败,请联系客服!"); }finally { return mp; } } /** * 网络文件转base64字符串 * @param netUrl 网络url * @return base64字符串 * @throws Exception */ public static String netFileToBase64(String netUrl) throws Exception { URL url = new URL(netUrl); //将图片文件转化为字节数组字符串,并对其进行Base64编码处理 log.info("图片的路径为:" + url.toString()); //打开链接 HttpURLConnection conn = null; try { conn = (HttpURLConnection) url.openConnection(); //设置请求方式为"GET" conn.setRequestMethod("GET"); //超时响应时间为5秒 conn.setConnectTimeout(5 * 1000); //通过输入流获取图片数据 InputStream inStream = conn.getInputStream(); //得到图片的二进制数据,以二进制封装得到数据,具有通用性 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); //创建一个Buffer字符串 byte[] buffer = new byte[1024]; //每次读取的字符串长度,如果为-1,代表全部读取完毕 int len = 0; //使用一个输入流从buffer里把数据读取出来 while ((len = inStream.read(buffer)) != -1) { //用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 outStream.write(buffer, 0, len); } //关闭输入流 inStream.close(); byte[] data = outStream.toByteArray(); //对字节数组Base64编码 BASE64Encoder encoder = new BASE64Encoder(); String base64 = encoder.encode(data).replaceAll("[\\s*\t\n\r]", ""); log.info("网络文件[{}]编码成base64字符串:[{}]"+url.toString()+base64); //返回Base64编码过的字节数组字符串 return base64; } catch (IOException e) { e.printStackTrace(); throw new Exception("图片上传失败,请联系客服!"); } } /** * 将base64字符串,生成文件 * @param fileBase64String base64文件字符串 * @param filePath 路径 * @param fileName 文件名称 * @return 文件 */ public static File convertBase64ToFile(String fileBase64String, String filePath, String fileName) { BufferedOutputStream bos = null; FileOutputStream fos = null; File file = null; try { File dir = new File(filePath); //判断文件目录是否存在 if (!dir.exists() && dir.isDirectory()) { dir.mkdirs(); } BASE64Decoder decoder = new BASE64Decoder(); byte[] bfile = decoder.decodeBuffer(fileBase64String); file = new File(filePath + File.separator + fileName); fos = new FileOutputStream(file); bos = new BufferedOutputStream(fos); bos.write(bfile); return file; } catch (Exception e) { e.printStackTrace(); return null; } finally { if (bos != null) { try { bos.close(); } catch (IOException e1) { e1.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } public static void main(String[] args) throws Exception { String filePath = "C:\\Users\\zwsky\\Desktop\\testImg\\22.jpg"; String base64Str = FileBase64Util.convertFileToBase64(filePath); log.info("----base64Str:{}",base64Str); log.info("------"); String localFilePath = "C:\\Users\\zwsky\\Desktop\\testImg"; FileBase64Util.convertBase64ToFile(base64Str,localFilePath,"zwtest.JPG"); log.info("------end---------"); /** //String localFilePath = LocalHostUtil.getTmpDir(); String localFilePath = "D:/application/bm/tmpDir"; String netUrl = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1583992587635&di=df289355a4a4ae94c9ce6d2a229dd090&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180228%2F75e94470278748ad9132eb3443949e50.jpeg"; Map<String,String> mp = FileBase64Util.netUrlToBase64(netUrl); log.info("--mp:{}",mp.toString()); String netBase64Str = FileBase64Util.netFileToBase64(netUrl); log.info("-------:{}",netBase64Str); File testFile = FileBase64Util.convertBase64ToFile(netBase64Str,localFilePath,"netTest.jpeg"); **/ /** MultipartFile String strUrl = "F:\\测试图片.jpg"; File file = new File(strUrl); InputStream inputStream = new FileInputStream(file); MultipartFile multipartFile = new MockMultipartFile(testFile.getName(), testFile.getAbsolutePath(), null, inputStream); log.info("file转multipartFile成功. {}",multipartFile); **/ /** InputStream inputStream = new FileInputStream(testFile); MultipartFile multipartFile = new MockMultipartFile(testFile.getName(), testFile.getAbsolutePath(), null, inputStream); **/ /** CommonsMultipartFile //form表单文件控件的名字随便起,//文件类型 ,//是否是表单字段,//原始文件名,//Interger的最大值可以存储两部1G的电影,//文件会在哪个目录创建 FileItem fileItem = new DiskFileItem("formFieldName", Files.probeContentType(testFile.toPath()), false, testFile.getName(), (int) testFile.length(), testFile.getParentFile()); // 最关键的一步:为DiskFileItem的OutputStream赋值 // IOUtils是org.apache.commons.io.IOUtils; // 与此类似的还有FileUtils IOUtils.copy(new FileInputStream(testFile), fileItem.getOutputStream()); MultipartFile cMultiFile = new CommonsMultipartFile(fileItem); **/ /** List<MultipartFile> fileList = new ArrayList<>(); fileList.add(multipartFile); UploadRequest uploadRequest = new UploadRequest(); uploadRequest.setObjectId("1"); uploadRequest.setObjectType(1); uploadRequest.setUploadFile(fileList); ResponseData responseData = ThirdPartyServeUtil.uploadFile(uploadRequest); **/ } } 坑点:
1、大小
对接的文档说传图片的base64字符串,还要传大小。也没说是这个图片文件流的大小,还是其他什么。害我一顿操作猛如虎,但是每次返回都是图片大小不匹配。然后就考虑是不是本生这个图片转base64字符串后的文件大小,又考虑什么转换最后又=,不算大小等等,代码里面的没有删除,大家可以看看注释,写了好几种方法求大小。
2、BASE64Encoder转base64字符串有换行
查询资料说:
根据RFC822规定,BASE64Encoder编码每76个字符,还需要加上一个回车换行
部分Base64编码的java库还按照这个标准实行
BASE64Encoder是JDK自带的,我用的是1.8的jdk。那么这里可见对接方不一定用的自带的,所以我得处理掉所有换行
基本上就这些,这里再说一嘴,实际上不仅仅图片可以转base64字符串,其他文件也是可以。