读网文《将20M文件从30秒压缩到1秒,我是如何做到的?》做实验
先在微信公众号上看到网文《将20M文件从30秒压缩到1秒,我是如何做到的?》,然后在网上搜索了一下,看到了原文:https://www.jianshu.com/p/2e46ccb125ef
很惊奇他把时间压缩到了三十分之一,于是就有了做实验验证的想法。
我的实验对象是apache-tomcat-9.0.30.zip,Redis-x64-3.2.100.msi,Redis-x64-3.2.100.zip这三个文件,加起来21M,比作者的十张2M图片略多。
任务是把它们三个压缩成一个result.zip文件。
首先我实验的是rugularZip方法,也是作者提到的第一种方法:
// time elapsed:1s652ms
private boolean rugularZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile);
byte[] buffer=new byte[BUFFER_SIZE];
int readLen=0; try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ; for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
InputStream inputStream=new BufferedInputStream(new FileInputStream(fileWillZip));
String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); while((readLen=inputStream.read(buffer,0,BUFFER_SIZE))!=-1) {
zipOut.write(buffer,0,readLen);
}
inputStream.close(); }
} zipOut.close();
}catch(Exception e) {
e.printStackTrace();
return false;
} return true;
}
用时1秒652毫秒。
接下来实验的是bufferOuputZip方法,也就是作者提到的第二种方法:
// time elapsed:1s207ms
private boolean bufferOuputZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile);
byte[] buffer=new byte[BUFFER_SIZE];
int readLen=0; try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut) ; for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
InputStream inputStream=new BufferedInputStream(new FileInputStream(fileWillZip));
String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); while((readLen=inputStream.read(buffer,0,BUFFER_SIZE))!=-1) {
bufferedOutputStream.write(buffer,0,readLen);
}
inputStream.close();
}
} bufferedOutputStream.flush();
zipOut.close(); return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
}
用时1秒207毫秒,少了四分之一。
接下来实验作者提出的第三种方法:
// elapsed:1s188ms
private boolean nioChannalZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile); try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;
WritableByteChannel wChannel=Channels.newChannel(zipOut); for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
FileChannel readChannel=new FileInputStream(fileWillZip).getChannel(); String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); readChannel.transferTo(0, readChannel.size(),wChannel) ;
readChannel.close();
}
} wChannel.close();
zipOut.close(); return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
}
一秒188毫秒,没少多少。
接下来再看作者又提到了内存映射文件,他又说和第三种方法速度差不多哦,算了我就不试了。
作者最后又提到pip,我一看原来是用线程,这当然快了,因为主线程只要调用压缩线程就可以返回了,压缩线程消耗的时间不计算在主线程运行时间内,运行当然是秒回。
当然pip里面有个阻塞回调的过程,这消耗了一些时间。
更新DB,写文件都可以另起线程运行,这也是以空间换时间的方法之一。
完整程序:
package zip; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; // Used to zip a file
public class FileZipper {
private static final int BUFFER_SIZE = 1024; public boolean compressFilesToZip(String[] files,String zipfile) {
return threadZip(files,zipfile);
} private boolean threadZip(String[] fromFiles,String toFile) {
new ZipThread(fromFiles,toFile).start();;
return true;
} // elapsed:1s188ms
private boolean nioChannalZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile); try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;
WritableByteChannel wChannel=Channels.newChannel(zipOut); for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
FileChannel readChannel=new FileInputStream(fileWillZip).getChannel(); String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); readChannel.transferTo(0, readChannel.size(),wChannel) ;
readChannel.close();
}
} wChannel.close();
zipOut.close(); return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
} // time elapsed:1s207ms
private boolean bufferOuputZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile);
byte[] buffer=new byte[BUFFER_SIZE];
int readLen=0; try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut) ; for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
InputStream inputStream=new BufferedInputStream(new FileInputStream(fileWillZip));
String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); while((readLen=inputStream.read(buffer,0,BUFFER_SIZE))!=-1) {
bufferedOutputStream.write(buffer,0,readLen);
}
inputStream.close();
}
} bufferedOutputStream.flush();
zipOut.close(); return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
} // time elapsed:1s652ms
private boolean rugularZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile);
byte[] buffer=new byte[BUFFER_SIZE];
int readLen=0; try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ; for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
InputStream inputStream=new BufferedInputStream(new FileInputStream(fileWillZip));
String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); while((readLen=inputStream.read(buffer,0,BUFFER_SIZE))!=-1) {
zipOut.write(buffer,0,readLen);
}
inputStream.close(); }
} zipOut.close();
}catch(Exception e) {
e.printStackTrace();
return false;
} return true;
} /**
* change seconds to DayHourMinuteSecond format
*
* @param startMs
* @param endMs
* @return
*/
private static String ms2DHMS(long startMs, long endMs) {
String retval = null;
long secondCount = (endMs - startMs) / 1000;
String ms = (endMs - startMs) % 1000 + "ms"; long days = secondCount / (60 * 60 * 24);
long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
long minutes = (secondCount % (60 * 60)) / 60;
long seconds = secondCount % 60; if (days > 0) {
retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
} else if (hours > 0) {
retval = hours + "h" + minutes + "m" + seconds + "s";
} else if (minutes > 0) {
retval = minutes + "m" + seconds + "s";
} else if(seconds > 0) {
retval = seconds + "s";
}else {
return ms;
} return retval + ms;
} public static String calculateElaspedTime(long startMs) {
long endMs = System.currentTimeMillis();
return ms2DHMS(startMs,endMs);
} public static void main(String[] args) {
String[] files= {"D:\\usr\\apache-tomcat-9.0.30.zip",
"D:\\usr\\Redis-x64-3.2.100.msi",
"D:\\usr\\Redis-x64-3.2.100.zip"};
String zipfile="D:\\usr\\result.zip"; long startMs = System.currentTimeMillis();
FileZipper fz=new FileZipper();
boolean isCreated=fz.compressFilesToZip(files, zipfile);
if(isCreated) {
System.out.println("File:'"+zipfile+"' created,time elapsed:"+calculateElaspedTime(startMs));
}
}
}
package zip; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; public class ZipThread extends Thread{
private String[] files;
private String zipfile; public ZipThread(String[] files,String zipfile) {
this.files=files;
this.zipfile=zipfile;
} public void run() {
nioChannalZip(this.files,this.zipfile);
} private boolean nioChannalZip(String[] fromFiles,String toFile) {
File zipFile=new File(toFile); try {
ZipOutputStream zipOut=new ZipOutputStream(new FileOutputStream(zipFile)) ;
WritableByteChannel wChannel=Channels.newChannel(zipOut); for(String file:fromFiles) {
File fileWillZip=new File(file); if(fileWillZip.exists()) {
FileChannel readChannel=new FileInputStream(fileWillZip).getChannel(); String entryName=fileWillZip.getName();// entryName should be a valid filename,no path seperater allowed
zipOut.putNextEntry(new ZipEntry(entryName)); readChannel.transferTo(0, readChannel.size(),wChannel) ;
readChannel.close();
}
} wChannel.close();
zipOut.close(); return true;
}catch(Exception e) {
e.printStackTrace();
return false;
}
}
}
--END-- 2020-01-06 14:54
读网文《将20M文件从30秒压缩到1秒,我是如何做到的?》做实验的更多相关文章
- 压缩20M文件从30秒到1秒的优化过程
文章来源公众号:IT牧场 有一个需求需要将前端传过来的10张照片,然后后端进行处理以后压缩成一个压缩包通过网络流传输出去.之前没有接触过用Java压缩文件的,所以就直接上网找了一个例子改了一下用了,改 ...
- Pandas 基础(4) - 读/写 Excel 和 CSV 文件
这一节将分别介绍读/写 Excel 和 CSV 文件的各种方式: - 读入 CSV 文件 首先是准备一个 csv 文件, 这里我用的是 stock_data.csv, 文件我已上传, 大家可以直接下载 ...
- Unity shader 官网文档全方位学习(一)
转载:https://my.oschina.net/u/138823/blog/181131 摘要: 这篇文章主要介绍Surface Shaders基础及Examples详尽解析 What?? Sha ...
- 【VR】Leap Motion 官网文档 FingerModel (手指模型)
前言: 感谢关注和支持这个Leap Motion系列翻译的朋友们,非常抱歉因为工作原因非常久没有更新,今后这个翻译还会继续(除非官方直接给出中文文档).本篇献给大家的是 <FingerModel ...
- Spring Security 官网文档学习
文章目录 通过`maven`向普通的`WEB`项目中引入`spring security` 配置 `spring security` `configure(HttpSecurity)` 方法 自定义U ...
- Atitit 基于图片图像 与文档混合文件夹的分类
Atitit 基于图片图像 与文档混合文件夹的分类 太小的文档(txt doc csv exl ppt pptx)单独分类 Mov10KminiDoc 但是可能会有一些书法图片迁移,因为他们很微小,需 ...
- php 读取文件头判断文件类型的实现代码
php代码实现读取文件头判断文件类型,支持图片.rar.exe等后缀. 例子: <?php $filename = "11.jpg"; //为图片的路径可以用d:/uploa ...
- php通过文件头检测文件类型通用类(zip,rar…)(转)
在做web应用时候,通过web扩展名判断上存文件类型,这个是我们常使用的.有时候我们这样做还不完善.可能有些人上存一些文件,但是他通过修改 扩展名,让在我们的文件类型之内. 单实际访问时候又不能展示( ...
- 部署openstack的官网文档解读mysql的配置文件
部署openstack的官网文档解读mysql的配置文件(使用与ubutu和centos7等系统) author:headsen chen 2017-10-12 16:57:11 个人原创,严禁转载 ...
随机推荐
- 新司机的致胜法宝,使用ApexSql Log2018快速恢复数据库被删除的数据
作为开发人员,误操作数据delete.update.insert是最正常不过的了,比如: 删除忘记加where条件: 查询为了图方便按了F5,但是数据里面夹杂着delete语句. 不管是打着后发动机声 ...
- CSS学习第三天
定位布局: 相对定位:相对于自身的位置进行偏移position需要搭配left right top bottom position: relative; 绝对定位:相对于有position属 ...
- 2020-05-31:假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
福哥答案2020-05-31: 使用keys指令可以扫出指定模式的key列表.对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?这个时候你要回答redis关键的 ...
- PHP 开发工程师基础篇 - PHP 字符串
字符串 (String) 字符串是一系列字符的集合.如 “abc”. 在 PHP 中,一个字符代表一个字节,一个字节 (Byte) 有 8 比特 (bit). PHP 仅支持 256 字符集,因此 P ...
- 用WEB方式开发WPF桌面程序
因为疫情影响,公司裁员,结束了一年多的web开发经历,重新开始做桌面,新公司用的是WPF(居然用的是winform style...),当然这跟本文没有关系...上篇博客写的用后台api和前台浏览器控 ...
- SpringSecurity权限管理系统实战—七、处理一些问题
目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...
- 群晖系统设置自动拍摄共享文件夹快照的教程【江东网 JDX86.COM】
Snapshot Replication 是数据备份和还原的工具.企业需要数据保护以防止因意外删除.应用程序崩溃.数据损毁和病毒所造成的数据丢失. 1.在套件中心下载该套件 2.打开套件可以看到NAS ...
- Docker Run Cadvisor failed: inotify_add_watch /sys/fs/cgroup/cpuacct,cpu: no such file or directory
原文链接:https://blog.csdn.net/poem_2010/article/details/84836816 没有找这个文件, 这是一个bug,在系统中,是cpu,cpuacct 可以去 ...
- Javascript逻辑运算认识
1 - 运算符(操作符) 1.1 运算符的分类 运算符(operator)也被称为操作符,是用于实现赋值.比较和执行算数运算等功能的符号. JavaScript中常用的运算符有: 算数运算符 递增和递 ...
- 程序员小哥教你秋招拿大厂offer
快要到秋招了,对于应届生来说,秋招是一个特别重要的机会.对于社招同学来说,金九银十也是一个很好的跳槽窗口. 而我呢,因为是从上海到广州工作,就没有提前先把工作定下来.刚好也趁这个机会出去旅游了两个月. ...