前面介绍的文件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. vmware添加磁盘后linux无需重启识别的方法

    cd /sys/class/scsi_host/ [root@centos4 scsi_host]# ls host0 host1 host2 有几个host就刷几次 [root@centos4 sc ...

  2. python根据服务名获取服务启动路径

    #coding=utf8 import _winreg as winreg class Win32Environment: """Utility class to get ...

  3. Win10 + Visual Studio 2017 下 OpenCV无法显示图像的问题

    测试代码如下: #include "stdafx.h" #include<opencv2\opencv.hpp> #include<opencv2\highgui ...

  4. scn 时间

    Scn转换成时间: select to_char(scn_to_timestamp(3998591352171),'YYYY-MM-DD HH24:MI:SS') from dual: 时间转换成sc ...

  5. 单个 LINQ to Entities 查询中的两个结构上不兼容的初始化过程中出现类型“XXXX”

    最近在做一个报表的时候,用EF使用了Contact方法,但是程式运行一直出错.最近终于找到原因了,写下来提醒下自己.好了,进入正题: 现在我举个栗子,目前数据库中有ParentStudent表和Sub ...

  6. iptables实现网络防火墙及地址转换

    iptables主机防火墙功能及常用命令 FSM:Finite State Machine 有限状态机 客户端:closed -->syn_sent -->established --&g ...

  7. Linux设备模型:基础篇

    linux提供了新的设备模型:总线(bus).设备(device).驱动(driver).其中总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连:设备是对于一个设备的详细信息描述,驱动 ...

  8. MyEclipse 2015反编译插件安装

    本文转自 MyEclipse 2015反编译插件安装 分享一下下载插件的地址,百度网盘:链接:http://pan.baidu.com/s/1nturiAH 密码:yk73 其次:我来说下具体操作步骤 ...

  9. Spring的控制反转和依赖注入

    Spring的官网:https://spring.io/ Struts与Hibernate可以做什么事? Struts, Mvc中控制层解决方案 可以进行请求数据自动封装.类型转换.文件上传.效验… ...

  10. POJ 3040 Allowance【贪心】

    POJ 3040 题意: 给奶牛发工资,每周至少 C 元.约翰手头上有面值V_i的硬币B_i个,这些硬币的最小公约数为硬币的最小面值.求最多能发几周? 分析: 贪心策略是使多发的面额最小(最优解).分 ...