Java开发笔记(九十一)IO流处理简单的数据压缩
前面介绍的文件I/O,不管是写入文本还是写入对象,文件中的数据基本是原来的模样,用记事本之类的文本编辑软件都能浏览个大概。这么存储数据,要说方便确实方便,只是不够经济划算,原因有二:其一,写入的数据可能存在大量重复的信息,但依原样写到文件的话,无疑保留了不少冗余数据,造成空间浪费;其二,写入的数据多以明文方式保存,容易产生信息泄露,安全性不高。为此Java提供了简单的压缩和解压工具,在将数据写入文件之前,先对数据进行压缩,再将压缩后的结果写到文件;同样读取压缩文件之时,先读出已压缩的数据,再将这些数据进行解压,解压后的结果即为最初的原始数据。
在IO流的家族体系中,压缩与解压操作需要GZIPOutputStream、GZIPInputStream、ByteArrayOutputStream、ByteArrayInputStream这四个工具类互相配合,分别简述如下:
GZIPOutputStream:压缩输出流。它吃进去的是原始数据的字节数组,拉出来的是字节数组输出流对象(压缩后的数据)。
ByteArrayOutputStream:字节数组输出流。它从压缩输出流获取压缩后的数据,并通过toByteArray方法输出字节数组信息。或者从压缩输入流获取解压后的数据,并通过toByteArray方法输出字节数组信息。
GZIPInputStream:压缩输入流。它吃进去的是字节数组输入流对象(压缩后的数据),拉出来的是解压后的字节数组(原始数据)。
ByteArrayInputStream:字节数组输入流。它输入压缩数据的字节数组,转成流对象后丢给压缩输入流。
上面的工具介绍描述看上去索然无味,确实要运用到实际案例中才比较好理解。接下来先来瞧瞧原始字符串是怎么变成压缩数据的,详细的压缩过程代码示例如下:
// 从字符串获得压缩后的字节数组
private static byte[] compress(String str) {
if (str==null || str.length()<=0) {
return null;
}
byte[] zip_bytes = null; // 声明压缩数据的字节数组
// 先构建字节数组输出流,再据此构建压缩输出流
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gos = new GZIPOutputStream(baos);) {
gos.write(str.getBytes()); // 往压缩输出流写入字节数组
gos.finish(); // 结束写入操作
zip_bytes = baos.toByteArray(); // 从字节数组输出流中获取字节数组信息
} catch (Exception e) {
e.printStackTrace();
}
return zip_bytes;
}
既已得到压缩后的字节数组,将其写入文件之中真是易如反掌,下面是往文件写入压缩数据的代码例子:
// 往文件写入压缩后的数据
private static void writeZipFile() {
String str = "白日依山尽,黄河入海流。\n欲穷千里目,更上一层楼。";
// 根据指定文件路径构建文件输出流对象
try (FileOutputStream fos = new FileOutputStream(mFileName)) {
// 从字符串获得压缩后的字节数组
byte[] zip_bytes = compress(str);
fos.write(zip_bytes); // 把字节数组写入文件输出流
} catch (Exception e) {
e.printStackTrace();
}
}
再来看看如何从压缩文件中读到解压后的原始数据,把压缩后的数据还原为初始字符串要复杂一些,需要ByteArrayInputStream、GZIPInputStream、ByteArrayOutputStream三个工具互相配合,具体的解压过程代码如下所示:
// 从压缩字节数组获得解压后的字符串
private static String uncompress(byte[] bytes) {
if (bytes==null || bytes.length<=0) {
return null;
}
byte[] unzip_bytes = null; // 声明解压数据的字节数组
// 分别构建字节数组输出流,以及字节数组输入流,并根据字节数组输入流构建压缩输入流
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
GZIPInputStream gis = new GZIPInputStream(bais);) {
byte[] buffer = new byte[1024];
while (true) {
// 从压缩输入流中读取数据到字节数组,并返回读到的数据长度
int length = gis.read(buffer);
if (length < 0) { // 未读到数据,表示已经读完了
break;
}
baos.write(buffer); // 往字节数组输出流写入字节数组
}
unzip_bytes = baos.toByteArray(); // 从字节数组输出流中获取字节数组信息
} catch (Exception e) {
e.printStackTrace();
}
return new String(unzip_bytes); // 把字节数组转换为字符串,并返回该字符串
}
利用刚刚编写的uncompress解压方法,很容易从压缩文件中得到原始字符串,下面是从压缩文件读取解压数据的代码例子:
// 从压缩文件中读取解压后的数据
private static void readZipFile() {
// 根据指定文件路径构建文件输入流对象
try (FileInputStream fis = new FileInputStream(mFileName)) {
// 分配长度为文件大小的字节数组。available方法返回当前未读取的大小
byte[] bytes = new byte[fis.available()];
fis.read(bytes); // 从文件输入流中读取字节数组
// 从压缩字节数组获得解压后的字符串
String content = uncompress(bytes);
System.out.println("content="+content);
} catch (Exception e) {
e.printStackTrace();
}
}
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(九十一)IO流处理简单的数据压缩的更多相关文章
- Java开发笔记(五十八)简单接口及其实现
前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...
- Java精选笔记_其他IO流(ObjectInputStream、DataInputStream、PrintStream、标准输入输出流)
其他IO流 ObjectInputStream和ObjectOutputStream 如果希望永久将对象转为字节数据写入到硬盘上,即对象序列化,可以使用ObjectOutputStream(对象输出流 ...
- Java开发笔记(序)章节目录
现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...
- Java开发笔记(九十)对象序列化及其读写
有些时候,开发者想把程序运行过程中的数据临时保存到文件,可是前面介绍的字符流和字节流,要么用来读写文本字符串,要么用来读写字节数组,并不能直接保存某个对象信息,因为对象里面包括成员属性和成员方法,单就 ...
- Java开发笔记(九十二)文件通道的基本用法
前面介绍的各色流式IO在功能方面着实强大,处理文件的时候该具备的操作应有尽有,可流式IO在性能方面不尽如人意,它的设计原理使得实际运行效率偏低,为此从Java4开始增加了NIO技术,通过全新的架构体系 ...
- Java开发笔记(八十八)文件字节I/O流
前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...
- Java开发笔记(八十五)通过字符流读写文件
前面介绍了文件的信息获取.管理操作,以及目录下的文件遍历,那么文件内部数据又是怎样读写的呢?这正是本文所要阐述的内容.File工具固然强大,但它并不能直接读写文件,而要借助于其它工具方能开展读写操作. ...
- Java开发笔记(七十二)Java8新增的流式处理
通过前面几篇文章的学习,大家应能掌握几种容器类型的常见用法,对于简单的增删改和遍历操作,各容器实例都提供了相应的处理方法,对于实际开发中频繁使用的清单List,还能利用Arrays工具的asList方 ...
- Java开发笔记(九十五)NIO配套的文件工具Files
NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths.路径工具Path.文件组工具Files.先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的 ...
随机推荐
- Linux设备驱动之Ioctl控制【转】
转自:http://www.cnblogs.com/geneil/archive/2011/12/04/2275372.html 大部分驱动除了需要具备读写设备的能力之外,还需要具备对硬件控制的能力. ...
- sqlserver 备份 与 还原
背景 真是够懒得,一看这个内容,如此简单.当时的想法就是网上教程一堆,全记下来有啥意思,只是记录了要点.不过写到这里,也就写个别的吧.sqlserver与Oracle比起来,我感觉有个重要差距就是存储 ...
- openwrt 中route配置
route配置项默认保存在文件 /etc/config/network 中. 配置route的接口“interface” 使用的协议需要为dhcp才可. config interface 'wan' ...
- CentOS 6.5使用Corosync + pacemaker实现httpd服务的高可用
Corosync:它属于OpenAIS(开放式应用接口规范)中的一个项目corosync一版本中本身不具备投票功能,到了corosync 2.0之后引入了votequorum子系统也具备了投票功能了, ...
- jmeter之正则表达式
一.Jmeter关联的方式: Jmeter中关联可以在需要获取数据的请求上 右键-->后置处理器 选择需要的关联方式,如下图有很多种方法可以提取动态变化数据: 二.正则表达式提取器: 1.比如需 ...
- keras2.0的一些变化
keras 变化太快了https://github.com/fchollet/keras/wiki/Keras-2.0-release-notes
- webpack 3之hash、chunkhash和contenthash三者的区别
在使用webpack 3中,文件名的hash值可以有三种hash生成方式,那具体使用哪一种呢? 1.hash 如果都使用hash的话,所有文件的hash都是一样的,而且每次修改任何一个文件,所有文件名 ...
- php和NodeJs共存的开发环境
1 折腾 php nodejs 到一起 nodejs当然很火,就像着火了一样,但是必须承认要搭建一个前端的demo开发环境还是PHP靠谱, windows下可以非常的集成套件,比如http://www ...
- C++ code:prime decision
1 判断一个数是否为素数 对于判断一个数m是否为素数,最朴素的方式是按照素数的定义,试除以从2开始到m-1的整数,倘若无一例外地不能整除,则该数必为素数. #include<iostream&g ...
- python 全栈开发,Day28(复习,os模块,导入模块import和from)
一.复习 collections 增加了一些扩展数据类型 :namedtuple orderdict defaltdict队列和栈time 时间 三种格式 : 时间戳 结构化 字符串random 随机 ...