java原生文件打包
一、背景
前端时间,自己做的项目需要打包功能,不想再引外部的jar包
便用java.util.zip做了下该功能
二、适用场景
生成多个word、excel、xml等文件,并要求打包下载的情形
例:项目信息的多选导出word
三、实现
实现分为三个部分,分别是
1、将字符串保存为文件,都是最基本的IO操作
/** * @Description 将字符串保存为文件 * @author liuy-8 * @date 2015年5月20日 下午1:48:18 * @param filePath * @param content */ public static void saveFile(String filePath, String content){ File file = new File(filePath); FileWriter fw = null; //这里没有使用BufferWrite,是因为数据是一次性写入 //BufferWrite的优势在于调用write方法时,使用缓冲区 //而FileWriter每次调用write方法,都调用StreamEncoder的write方法 try { fw = new FileWriter(file);//缓冲区1024字符 fw.write(content); fw.flush(); } catch (IOException e) { e.printStackTrace(); } finally{ //关闭FileWriter try { if(null != fw) fw.close(); } catch (IOException e) { e.printStackTrace(); } } }
2、扫描指定文件夹下所有的文件,准备压缩包的写入工作
这一部分依然是基本的IO操作,要注意安全关闭输入输出流,打开与关闭的顺序
/** * @Description 获取文件夹中所有文件路径 * @author liuy-8 * @date 2015年5月27日 下午5:25:24 * @param folderPath 文件夹路径 * @return 文件夹中所有文件路径 */ public static List<String> getFilesPath(String folderPath){ List<String> filesPath = new ArrayList<String>(); File folder = new File(folderPath); File[] fileList = folder.listFiles(); for(File file : fileList){ if(file.isDirectory()){ //是文件夹,递归遍历 filesPath.addAll(getFilesPath(file.getPath())); }else{ //是文件,加入文件列表 filesPath.add(file.getPath()); } } return filesPath; } /** * @Description 压缩文件夹 * @author liuy-8 * @date 2015年5月26日 下午1:42:00 * @param folderPath 文件夹路径 * @param zipFilePath 压缩文件路径 */ public static void folder2Zip(String folderPath, String zipFilePath){ //获取当前系统文件分隔符 String fileSeparator = System.getProperty("file.separator"); //若传入路径最后没有文件分隔符,加上 if(folderPath.lastIndexOf(fileSeparator) != (folderPath.length() - 1)){ folderPath = folderPath + fileSeparator; } //获取文件夹下所有文件路径 List<String> filesPath = getFilesPath(folderPath); //文件输出流 FileOutputStream fos = null; //缓冲输出流 BufferedOutputStream bos = null; //zip输出流 ZipOutputStream zos = null; try { fos = new FileOutputStream(zipFilePath); bos = new BufferedOutputStream(fos); zos = new ZipOutputStream(bos); for(String filePath : filesPath){ //将文件写入zip输出流 writeFile2Zip(folderPath, filePath, zos); } zos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ //关闭zip输出流 try { if(null != zos){ zos.close(); } } catch (IOException e) { e.printStackTrace(); } //关闭缓冲输出流 try { if(null != bos){ bos.close(); } } catch (IOException e) { e.printStackTrace(); } //关闭文件输出流 try { if(null != fos){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } } }
3、将文件依次写入zip输出流
在第二步已经用ZipOutputStream创建了压缩文件的输出流,这一步里,每个文件都要对应一个ZipEntry对象
要将这个对象加入到压缩文件的输出流中后再写入数据,并且写完数据必须在输出流中关闭该ZipEntry对象
这里有2个容易出错的地方:
一是ZipEntry对象需要一个路径,这个路径是相对于压缩文件夹的相对路径,用来保证子文件夹文件的顺利压入
二是往zip输出流中写入的字节的时候,要判断循环读取字节时文件输入流中读取了多少字节长度,读多少写多少,不然在文件尾部会出现错误数据
/** * @Description 将文件写入zip输出流 * @author liuy-8 * @date 2015年5月27日 下午5:23:42 * @param folderPath 待压缩文件夹路径 * @param filePath 待写入文件 * @param zos zip输出流 */ private static void writeFile2Zip(String folderPath, String filePath, ZipOutputStream zos){ //缓冲区 byte[] bs = new byte[1024]; //获取文件的相对路径 String entryName = filePath.substring(filePath.indexOf(folderPath) + folderPath.length()); //创建zip实体 ZipEntry entry = new ZipEntry(entryName); //输入流 FileInputStream fis = null; //缓冲输入流 BufferedInputStream bis = null; try { //将zip实体加入zip输出流 zos.putNextEntry(entry); fis = new FileInputStream(filePath); bis = new BufferedInputStream(fis); //写入zip输出流 int len = 0; while((len = bis.read(bs, 0, 1024)) > 0){ zos.write(bs, 0, len); } zos.flush(); } catch (IOException e) { e.printStackTrace(); } finally{ //关闭entity try { zos.closeEntry(); } catch (IOException e) { e.printStackTrace(); } //关闭BufferedInputStream try { if(null != bis){ bis.close(); } } catch (IOException e) { e.printStackTrace(); } //关闭FileInputStream try { if(null != fis){ bis.close(); } } catch (IOException e) { e.printStackTrace(); } } }
此类已封装为GlodonFileUtil,有需要找我要即可