package cn.timer.api.utils.aliyun; import java.io.*; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import cn.timer.api.config.sftp.SftpConfiguration; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.jcraft.jsch.ChannelSftp; import io.swagger.models.auth.In; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.bouncycastle.jce.exception.ExtIOException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.event.ProgressEvent; import com.aliyun.oss.event.ProgressEventType; import com.aliyun.oss.event.ProgressListener; import com.aliyun.oss.model.DeleteObjectsRequest; import com.aliyun.oss.model.DeleteObjectsResult; import com.aliyun.oss.model.GetObjectRequest; import com.aliyun.oss.model.ListObjectsRequest; import com.aliyun.oss.model.OSSObject; import com.aliyun.oss.model.OSSObjectSummary; import com.aliyun.oss.model.ObjectListing; import com.aliyun.oss.model.ObjectMetadata; import com.aliyun.oss.model.PutObjectRequest; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.timer.api.utils.Result; import cn.timer.api.utils.ResultUtil; import javax.servlet.http.HttpServletResponse; /** * OSS接口操作示例 1.创建空间 2.上传文件 3.下载文件 * * @author dsc */ @Component public class OSSUtil { @Value("${config-8timer.Aliyun.endpoint}") private String endpoint; @Value("${config-8timer.Aliyun.ACCESSKEY_ID}") private String accessKeyId; @Value("${config-8timer.Aliyun.SECRET}") private String accessKeySecret; @Value("${config-8timer.Aliyun.bucketName}") private String bucketName; @Value("${config-8timer.Aliyun.bucketName_pri}") private String bucketName_pri; @Value("${config-8timer.Aliyun.project_package}") private String project_package; @Value("${config-8timer.Aliyun.expirationTime}") private String expirationTime; @Value("${config-8timer.Aliyun.expirationTime_pri}") private String expirationTime_pri; @Value("${zip.path}") private String zipPath; @Autowired private SftpConfiguration config; /** * 1.创建储存空间 sout控制台輸出 储存空间名 * * @param bucketName OSS空间名 * @return 成功信息 */ public Result<Void> createZone(String bucketName) { // Endpoint以杭州为例,其它Region请按实际情况填写。 // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 // https://ram.console.aliyun.com 创建RAM账号。 // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 创建存储空间。 ossClient.createBucket(bucketName); // 关闭OSSClient。 ossClient.shutdown(); // 控制台输出空间名 Logoutput("bucketName:" + bucketName); // 返回成功 return ResultUtil.success("创建OSS空间成功"); } /** * 2.上传文件到8time-v2 * * @param path 上传路径(用'/'分包) * @param ins 输入流 * @return */ public String uploadFile(File path, InputStream ins) { // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 // String objectName = "8time-v2/test/123.jpg"; // 创建OSSClient实例。 Logoutput(endpoint); Logoutput(accessKeyId); Logoutput(accessKeySecret); OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 创建PutObjectRequest对象。 // 项目名+用户公司id+模块名+文件夹名+文件名 PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path.getPath(), ins); // [file1,file2,file3],["mk1/img","mk1"] // 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。 // ObjectMetadata metadata = new ObjectMetadata(); // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, // StorageClass.Standard.toString()); // metadata.setObjectAcl(CannedAccessControlList.Private); // putObjectRequest.setMetadata(metadata); // 上传文件。 ossClient.putObject(putObjectRequest); // 设置URL过期时间为100年。 1s 1h 1d 1y 100y // Date expiration = new Date(new Date().getTime() + 1000L * 3600 * 24 * 365 * 100); Date now = new Date(); Date expiration = DateUtil.offset(now, DateField.YEAR, 100); // 一百年之后过期 // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。 URL url = ossClient.generatePresignedUrl(bucketName, path.getPath(), expiration); Logoutput(String.valueOf(url)); // 关闭OSSClient。 ossClient.shutdown(); // 返回上传成功的文件名 return url.toString().substring(0, url.toString().lastIndexOf("?")); } /** * 3.上传文件到8time-v2-private * * @param path 上传路径(用'/'分包) * @param ins 输入流 * @return 文件路径 */ public String uploadPrivateFile(String path, InputStream ins) { // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 // String objectName = "8time-v2/test/123.jpg"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 创建PutObjectRequest对象。 // 项目名+用户公司id+模块名+文件夹名+文件名 PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName_pri, path, ins); // [file1,file2,file3],["mk1/img","mk1"] // 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。 // ObjectMetadata metadata = new ObjectMetadata(); // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, // StorageClass.Standard.toString()); // metadata.setObjectAcl(CannedAccessControlList.Private); // putObjectRequest.setMetadata(metadata); // 上传文件。 ossClient.putObject(putObjectRequest); // 设置URL过期时间为10分钟 Date expiration = new Date(new Date().getTime() + 1000 * 600); // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。 URL url = ossClient.generatePresignedUrl(bucketName_pri, path, expiration); Logoutput(String.valueOf(url)); // 关闭OSSClient。 ossClient.shutdown(); // 返回上传成功的文件名 return path; } /** * 4.从OSS下载文件 * * @param path 本地储存文件路径 * @param orgCode 公司id * @param dir 包名 * @param fileName 文件名 * @param moudle 模块名 * @return 完整文件名 */ public Result<String> downloadFile(String orgCode, String moudle, String dir, String fileName, String path) { // <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 // String objectName = "8time-v2/test/123.jpg"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。 ossClient.getObject( new GetObjectRequest(bucketName, project_package + orgCode + "/" + moudle + "/" + dir + "/" + fileName), new File(path + fileName)); // 关闭OSSClient。 ossClient.shutdown(); // 完整路径的文件名 Logoutput("objectName:" + project_package + orgCode + "/" + moudle + "/" + dir + "/" + fileName); Logoutput("path:" + path + fileName); // 返回成功的本地路径 return ResultUtil.success(path + fileName); } public Result<BufferedReader> downloadFile(String objectName) throws IOException { // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。 OSSObject ossObject = ossClient.getObject(bucketName, objectName); // 读取文件内容。 System.out.println("Object content:"); BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent())); while (true) { String line = reader.readLine(); if (line == null) break; System.out.println("\n" + line); } // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。 reader.close(); // 关闭OSSClient。 ossClient.shutdown(); return ResultUtil.data(reader, "下载成功"); } public InputStream downloadFileInputStream(String objectName) { // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。 OSSObject ossObject = ossClient.getObject(bucketName, objectName); // 关闭OSSClient。 //ossClient.shutdown(); return ossObject.getObjectContent(); } /** * 文件输入流批量上传 * * @param request 获取参数 * @param files 批量文件 * @return 返回上传成功或失败的信息 */ public String uploadFile(MultipartHttpServletRequest request, List<MultipartFile> files) { OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); String newFileName = null; URL url = null; try { // 上传文件 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver( request.getSession().getServletContext()); // 判断 request 是否有文件上传,即多部分请求 if (multipartResolver.isMultipart(request)) { // 转换成多部分request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; // 取得request中的所有文件名 Iterator<String> iter = multiRequest.getFileNames(); // 此处上传单个文件,如需多个文件改为while循环 while (iter.hasNext()) { // 取得上传文件 files = multiRequest.getFiles(iter.next()); if (files != null) { // 取得当前上传文件的文件名称 String myFileName = null; for (MultipartFile file : files) { myFileName = file.getOriginalFilename(); // 如果名称不为“”,说明该文件存在,否则说明该文件不存在 if (StrUtil.isNotEmpty(myFileName.trim())) { newFileName = System.currentTimeMillis() + myFileName.substring(myFileName.lastIndexOf(".")); // 上传客户端文件到oss,如直接上传服务器文件到oss,可使用new FileInputStream( new File("服务器文件路径")) ossClient.putObject(bucketName, newFileName, file.getInputStream()); // 设置URL过期时间为100年。 1s 1h 1d 1y 100y Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime)); // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。 url = ossClient.generatePresignedUrl(bucketName, newFileName, expiration); Logoutput(String.valueOf(url)); } } } } } } catch (IOException e) { e.getStackTrace(); } finally { // 关闭ossClient if (null != ossClient) ossClient.shutdown(); } return url.toString(); /* * if (file == null || file.getSize() <= 0) { return * ResultUtil.error("上传的文件为空,请重新选择!"); } else { try { * OSSUtil.uploadFile(userBean.getOrgCode(), className, * file.getOriginalFilename(), file.getInputStream()); } catch (IOException e) { * e.printStackTrace(); } return ResultUtil.success("上传成功"); } */ } /** * 获取8time-v2文件的url * * @return url地址 */ public String getUrl(String path) { // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 设置URL过期时间为100年。 1s 1h 1d 1y 10y Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime)); // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。 URL url = ossClient.generatePresignedUrl(bucketName, path, expiration); Logoutput(String.valueOf(url)); // 关闭OSSClient。 ossClient.shutdown(); return url.toString(); } /** * 获取8time-v2-private文件的url * * @return url地址 */ public String getUrlP(String path) { // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 设置URL过期时间为10分钟。 Date expiration = new Date(new Date().getTime() + Long.parseLong(expirationTime_pri)); // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。 URL url = ossClient.generatePresignedUrl(bucketName, path, expiration); Logoutput(String.valueOf(url)); // 关闭OSSClient。 ossClient.shutdown(); return url.toString(); } /** * 删除单个 * * @param objectName 文件名 */ public void delSingleFile(String objectName) { // // Endpoint以杭州为例,其它Region请按实际情况填写。 // String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。 // String accessKeyId = "<yourAccessKeyId>"; // String accessKeySecret = "<yourAccessKeySecret>"; // String bucketName = "<yourBucketName>"; // String objectName = "<yourObjectName>"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。 ossClient.deleteObject(bucketName, objectName); // 关闭OSSClient。 ossClient.shutdown(); } /** * 删除多个文件 * * @param keys 需要删除的文件。 * @param quiet 返回模式。true表示简单模式,false表示详细模式。默认为详细模式。 * @return 删除结果。详细模式下为删除成功的文件列表,简单模式下为删除失败的文件列表。 */ public List<String> delFiles(List<String> keys, boolean quiet) { // // Endpoint以杭州为例,其它Region请按实际情况填写。 // String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。 // String accessKeyId = "<yourAccessKeyId>"; // String accessKeySecret = "<yourAccessKeySecret>"; // String bucketName = "<yourBucketName>"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 删除文件。key等同于ObjectName,表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 // List<String> keys = new ArrayList<String>(); // keys.add("key0"); // keys.add("key1"); // keys.add("key2"); DeleteObjectsResult deleteObjectsResult = ossClient .deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys).withQuiet(quiet)); List<String> deletedObjects = deleteObjectsResult.getDeletedObjects(); // 关闭OSSClient。 ossClient.shutdown(); return deletedObjects; } /** * 删除指定前缀(prefix)的文件 * * @param prefix */ public void delPrefixWith(String prefix) { // // Endpoint以杭州为例,其它Region请按实际情况填写。 // String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; // // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 // // https://ram.console.aliyun.com 创建RAM账号。 // String accessKeyId = "<yourAccessKeyId>"; // String accessKeySecret = "<yourAccessKeySecret>"; // String bucketName = "<yourBucketName>"; // // // 指定前缀。 // final String prefix = "<yourkeyPrefix>"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 列举所有包含指定前缀的文件并删除。 String nextMarker = null; ObjectListing objectListing = null; do { ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withPrefix(prefix) .withMarker(nextMarker); objectListing = ossClient.listObjects(listObjectsRequest); if (objectListing.getObjectSummaries().size() > 0) { List<String> keys = new ArrayList<String>(); for (OSSObjectSummary s : objectListing.getObjectSummaries()) { Logoutput("key name: " + s.getKey()); keys.add(s.getKey()); } DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(keys); ossClient.deleteObjects(deleteObjectsRequest); } nextMarker = objectListing.getNextMarker(); } while (objectListing.isTruncated()); // 关闭OSSClient。 ossClient.shutdown(); } /* * (跨域资源) // Endpoint以杭州为例,其它Region请按实际情况填写。 String endpoint = * "http://oss-cn-hangzhou.aliyuncs.com"; // * 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 * https://ram.console.aliyun.com 创建RAM账号 String accessKeyId = * "<yourAccessKeyId>"; String accessKeySecret = "<yourAccessKeySecret>"; String * bucketName = "<yourBucketName>"; * * // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, * accessKeyId, accessKeySecret); * * SetBucketCORSRequest request = new SetBucketCORSRequest(bucketName); * * // 跨域资源共享规则的容器,每个存储空间最多允许10条规则。 ArrayList<CORSRule> putCorsRules = new * ArrayList<CORSRule>(); * * CORSRule corRule = new CORSRule(); * * ArrayList<String> allowedOrigin = new ArrayList<String>(); // 指定允许跨域请求的来源。 * allowedOrigin.add( "http://www.b.com"); * * ArrayList<String> allowedMethod = new ArrayList<String>(); // * 指定允许的跨域请求方法(GET/PUT/DELETE/POST/HEAD)。 allowedMethod.add("GET"); * * ArrayList<String> allowedHeader = new ArrayList<String>(); // * 是否允许预取指令(OPTIONS)中Access-Control-Request-Headers头中指定的Header。 * allowedHeader.add("x-oss-test"); * * ArrayList<String> exposedHeader = new ArrayList<String>(); // * 指定允许用户从应用程序中访问的响应头。 exposedHeader.add("x-oss-test1"); // * AllowedOrigins和AllowedMethods最多支持一个星号(*)通配符。星号(*)表示允许所有的域来源或者操作。 * corRule.setAllowedMethods(allowedMethod); * corRule.setAllowedOrigins(allowedOrigin); // * AllowedHeaders和ExposeHeaders不支持通配符。 corRule.setAllowedHeaders(allowedHeader); * corRule.setExposeHeaders(exposedHeader); // * 指定浏览器对特定资源的预取(OPTIONS)请求返回结果的缓存时间,单位为秒。 corRule.setMaxAgeSeconds(10); * * // 最多允许10条规则。 putCorsRules.add(corRule); // 已存在的规则将被覆盖。 * request.setCorsRules(putCorsRules); ossClient.setBucketCORS(request); * * // 关闭OSSClient。 ossClient.shutdown(); */ public void download(String url, String savePath) { // Endpoint以杭州为例,其它Region请按实际情况填写。 // String endpoint = "http://oss-cn-shenzhen.aliyuncs.com"; // // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 // // https://ram.console.aliyun.com 创建RAM账号。 // String accessKeyId = "LTAI4FuaShJWQ1dggsFWG5CC"; // String accessKeySecret = "EJ6qToT4T4u0B5Rb6qrta9WkyGHvGR"; // String bucketName = "8time-v2"; // String objectName = "8timer2.0/117/test/测试.pdf"; OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // String url = "http://8time-v2.oss-cn-shenzhen.aliyuncs.com/8timer2.0/310/qyxx/filepath/158872957193802f4a85a-9dd9-483a-9049-86fac5c73bd5.pdf?Expires=4747952308&OSSAccessKeyId=LTAI4FuaShJWQ1dggsFWG5CC&Signature=z%2FNIX0RrxnLuBLAS9olPpxxsCrI%3D"; try { // 带进度条的下载。 ObjectMetadata a = ossClient.getObject(new GetObjectRequest(new URL(url), null), new File(savePath)); System.err.println(a); // new File("C:\\Users\\Lenovo\\Desktop\\8小时\\test2.pdf")); // // 带进度条的下载。 // ossClient.getObject(new GetObjectRequest(bucketName, objectName).<GetObjectRequest>withProgressListener( // new GetObjectProgressListener()), new File("C:\\Users\\Lenovo\\Desktop\\8小时\\test.pdf")); } catch (Exception e) { e.printStackTrace(); } // 关闭OSSClient。 ossClient.shutdown(); } static class GetObjectProgressListener implements ProgressListener { private long bytesRead = 0; private long totalBytes = -1; private boolean succeed = false; @Override public void progressChanged(ProgressEvent progressEvent) { long bytes = progressEvent.getBytes(); ProgressEventType eventType = progressEvent.getEventType(); switch (eventType) { case TRANSFER_STARTED_EVENT: System.out.println("Start to download......"); break; case RESPONSE_CONTENT_LENGTH_EVENT: this.totalBytes = bytes; System.out.println(this.totalBytes + " bytes in total will be downloaded to a local file"); break; case RESPONSE_BYTE_TRANSFER_EVENT: this.bytesRead += bytes; if (this.totalBytes != -1) { int percent = (int) (this.bytesRead * 100.0 / this.totalBytes); System.out.println(bytes + " bytes have been read at this time, download progress: " + percent + "%(" + this.bytesRead + "/" + this.totalBytes + ")"); } else { System.out.println(bytes + " bytes have been read at this time, download ratio: unknown" + "(" + this.bytesRead + "/...)"); } break; case TRANSFER_COMPLETED_EVENT: this.succeed = true; System.out.println("Succeed to download, " + this.bytesRead + " bytes have been transferred in total"); break; case TRANSFER_FAILED_EVENT: System.out.println("Failed to download, " + this.bytesRead + " bytes have been transferred"); break; default: break; } } public boolean isSucceed() { return succeed; } } @Value("${config-8timer.environmental-science}") public String environmental_science; public void Logoutput(String science) { if (!("pro").equals(environmental_science)) { System.out.println(science); } else { System.out.println(""); } } /** * @Author wgd * @Description 创建zip * @Date 2021/12/2 18:06 **/ public String createZip(Map<String, String> urlMap) throws IOException { DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String fileName = dateFormat.format(new Date()) + ".zip"; FileOutputStream fos = null; ZipOutputStream zos = null; BufferedInputStream inputStream; OSSObject ossObject; String Suffix; try { File folder = new File(zipPath); if(!folder.exists()&& !folder .isDirectory()){ folder.mkdirs(); } fos = new FileOutputStream(zipPath+fileName); zos = new ZipOutputStream(fos); OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); for (String m : urlMap.keySet()) { Suffix = urlMap.get(m).substring(urlMap.get(m).lastIndexOf(".")); ossObject = ossClient.getObject(bucketName, urlMap.get(m)); inputStream = new BufferedInputStream(ossObject.getObjectContent()); ZipEntry entry = new ZipEntry(m + Suffix); try { zos.putNextEntry(entry); int nNumber; byte[] buffer = new byte[4096]; while ((nNumber = inputStream.read(buffer)) > 0) { zos.write(buffer, 0, nNumber); } } catch (IOException e) { throw new IOException("写入失败");//TODO 应作为自定义异常 } finally { try { inputStream.close(); } catch (IOException e) { throw new IOException("关闭失败");//TODO 应作为自定义异常 } } } ossClient.shutdown(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { // 关闭创建的流对象 try { if (zos != null) { zos.closeEntry(); zos.close(); } if (fos != null) { fos.close(); } } catch (IOException e) { throw new IOException("关闭失败");//TODO 应作为自定义异常 } } return fileName; } }