前面介绍的文件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流处理简单的数据压缩的更多相关文章

  1. Java开发笔记(五十八)简单接口及其实现

    前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...

  2. Java精选笔记_其他IO流(ObjectInputStream、DataInputStream、PrintStream、标准输入输出流)

    其他IO流 ObjectInputStream和ObjectOutputStream 如果希望永久将对象转为字节数据写入到硬盘上,即对象序列化,可以使用ObjectOutputStream(对象输出流 ...

  3. Java开发笔记(序)章节目录

    现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...

  4. Java开发笔记(九十)对象序列化及其读写

    有些时候,开发者想把程序运行过程中的数据临时保存到文件,可是前面介绍的字符流和字节流,要么用来读写文本字符串,要么用来读写字节数组,并不能直接保存某个对象信息,因为对象里面包括成员属性和成员方法,单就 ...

  5. Java开发笔记(九十二)文件通道的基本用法

    前面介绍的各色流式IO在功能方面着实强大,处理文件的时候该具备的操作应有尽有,可流式IO在性能方面不尽如人意,它的设计原理使得实际运行效率偏低,为此从Java4开始增加了NIO技术,通过全新的架构体系 ...

  6. Java开发笔记(八十八)文件字节I/O流

    前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...

  7. Java开发笔记(八十五)通过字符流读写文件

    前面介绍了文件的信息获取.管理操作,以及目录下的文件遍历,那么文件内部数据又是怎样读写的呢?这正是本文所要阐述的内容.File工具固然强大,但它并不能直接读写文件,而要借助于其它工具方能开展读写操作. ...

  8. Java开发笔记(七十二)Java8新增的流式处理

    通过前面几篇文章的学习,大家应能掌握几种容器类型的常见用法,对于简单的增删改和遍历操作,各容器实例都提供了相应的处理方法,对于实际开发中频繁使用的清单List,还能利用Arrays工具的asList方 ...

  9. Java开发笔记(九十五)NIO配套的文件工具Files

    NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths.路径工具Path.文件组工具Files.先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的 ...

随机推荐

  1. Python单元测试unittest - 单元测试框架

    一.unittest简介 unitest单元测试框架最初是有JUnit的启发,它支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中,以及测试与报告框架的独立性. 二.unittest相关概念 ...

  2. zabbix3.0.4关于java服务端程序内存溢出的处理

    关于java服务端程序内存溢出的处理 java服务端程序内存溢出会产生jvm.log文件,此时程序会挂掉,无法正常处理业务,需要重启服务 思路: 当存在jvm.log这个文件的时候则触发clean_j ...

  3. 在Mac上安装GTK(go语言GUI)

    1.在终端输入:xcode-select --install 安装command line工具, 如果安装了Xcode, 就直接跳过该步骤 2. 在终端输入:ruby -e "$(curl ...

  4. 转:vue+element实现树形组件

    项目中需要用到树形组件,在网上发现一个用vue+element实现的树形组件,现在记录下: demo地址:https://github.com/wilsonIs/vue-treeSelect

  5. CSS Grid 布局

    CSS Grid 布局是 CSS 中最强大的布局系统.与 flexbox 的一维布局系统不同,CSS Grid 布局是一个二维布局系统,也就意味着它可以同时处理列和行.通过将 CSS 规则应用于 父元 ...

  6. 使用Java类库POI生成简易的Excel报表

    使用Java类库POI生成简易的Excel报表 1.需求 1.数据库生成报表需要转义其中字段的信息.比如 1,有效 2.无效等 2.日期格式的自数据需要转义其格式. 3.标题的格式和数据的格式需要分别 ...

  7. PHP实现简单倒计时

    PHP实现倒计时代码示例如下: <?php $time1 = time(); $time2 = strtotime("2018-10-1"); $time3 = strtot ...

  8. Codeforces 448C Painting Fence(分治法)

    题目链接:http://codeforces.com/contest/448/problem/C 题目大意:n个1* a [ i ] 的木板,把他们立起来,变成每个木板宽为1长为 a [ i ] 的栅 ...

  9. Ext.Js核心函数( 三)

    ExtJs 核心函数简介 1.ExtJs提供的常用函数2.get.fly.getCmp.getDom.getBody.getDoc3.query函数和select函数4.encode函数和decode ...

  10. Emmet Cheat Sheet(Sublime编辑)

    快捷创建html标签 官网的Emmet Cheat Sheet :http://docs.emmet.io/cheat-sheet/ https://files.cnblogs.com/files/t ...