java流、序列化和相关类的用法

Reading time ~9 minutes

此文章为原创文章,引用请标记文章出处: java流、序列化和相关类的用法

本文主要介绍了阻塞流、非阻塞流、序列化和流工具的使用场景,但不介绍流的实现方式。

io流的结构

io流的层次结构

面向线程的、阻塞式I/O:java io

1.InputStream / Reader

对比InputStream和Reader所提供的方法, 这两个类的功能基本相同, 只是一个提供了字节byte读, 一个提供了字符char读. 除此之外, InputStream和Reader还支持几个方法来移动记录指针以实现跳读, 重复读等操作.

2.OutputStream / Writer

因为字符流直接以字符作为操作单位, 所以Writer可以用字符串来代替字符数组(以String对象作为参数).

如果进行IO是文本内容,则应该考虑使用字符流;如果进行IO的是二进制内容, 则应该考虑使用字节流.

3.处理流与节点流:

处理流与节点流都包含输入流和输出流;

处理流与节点流相比可以隐藏底层节点流的差异,对外提供更加统一的IO方法,让开发人员只需关心流的操作(使用更加简单, 执行效率更高).关闭最上层的处理流时, 系统会自动关闭该处理流包装的节点流;

4.内存操作流:

字节流以字节数组为节点:ByteArrayInputStream/ByteArrayOutputStream,

字符流以字符数组为节点:CharArrayReader/CharArrayWriter

将数据写入到内存中:ByteArrayInputStream、CharArrayReader

从内存中读取数据:ByteArrayOutputStream、CharArrayWriter

内存操作流一般在生成一些临时信息时才使用,而这些临时信息不需要文件存储起来,而且操作完就需要删除的信息。

5.缓冲流

BufferedInputStream 、BufferedOutputStream 、BufferedReader、BufferedWriter

四个缓冲流增加了缓冲功能, 可以提高IO效率, 但是需要使用flush()才可以将缓冲区的内容写入实际的物理节点.

6.转换流

java.io.InputStreamReader将字节输入流转换成字符输入流

java.io.OutputStreamWriter将字节输出流转换成字符输出流

7.管道流:

用于两个线程间的通信

PipedOutputStream、PipedInputStream

connection()将两个线程管道连接在一起,线程启动后自动进行管道的输入、输出操作。

8.打印流:

PrintStream、PrintWriter

输出信息,可以打印任何的数据类型,如小数、整数、字符串等。处理流

System.out(Eclipse控制台输出是普通颜色的字体)、System.err(Eclipse控制台输出是红色的字体)是PrintStream的对象,PrintStream又是OutputStream的子类。

System.in是InputStream类型的对象,完成从键盘读取数据

9.数据操作流

DataOutputStream、DataInputStream

平台无关的数据操作流,对数据按照一定的格式输入和输出,且输入和输出的格式要对应。

10.合并流

SequenceInputStream

将两个文件的内容合并成一个文件

11.压缩流

将文件或文件夹压缩成zip、jar、gzip格式的文件

zip: java.util.zip(ZipFile、ZipOutputStream、ZipInputStream、ZipEntry)

jar: java.util.jar(JarOutputStream、JarInputStream、JarFile、JarEntry)

gzip: java.util.zip(GZIPOutputStream、GZIPInputStream)

12.回退流

PushbackInputStream 、PushbackReader

如果在输入流中某个不需要的内容被读取进来,可以通过回退流把读取进来的某些数据重新退回到输入流的缓冲区中,需要设置退回缓冲区的大小(默认为1)。

13.对象流

ObjectOutputStream 、ObjectInputStream

一般结合序列化使用,对象的类名, 实例变量(基本类型/数组/引用对象)都会被序列化; 而方法/类变量(static)/transient实例变量都不会序列化.

面向块、非阻塞I/O:java nio

1.数据缓冲操作类:

ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer

缓冲区只能容纳特定的数据类型

2.通道Channel

多路复用的非阻塞 I/O 比面向线程的阻塞 I/O的可伸缩性更好,所有的内容都是先读取或写入到缓冲区中,再通过缓冲区读取或写入到内存。

FileChannel:用于读取、写入、映射和操作文件的通道,可以同时完成输出和输入数据

Pipe.SinkChannel, Pipe.SourceChannel:一个可写入的单向sink通道和一个可读取的单向 source通道组成的通道对

ServerSocketChannel,SocketChannel,DatagramChannel: 针对面向流的侦听套接字的可选择通道

3.FileLock

一个线程操作一个文件时不希望其它线程进行访问,可以通过FileLock锁定这个文件

4.编码转换操作

CharsetEncoder、CharsetDecoder

字节和 Unicode 字符之间转换的解码器和编码器

对象序列化

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流, 从而可以把这种二进制流持久的保存在磁盘上, 或通过网络将这种二进制流传输到另一个网络节点. 其他程序一旦获取到了这个二进制流, 都可以将他恢复成原先的Java对象.

像Date BigInteger这样的值类应该实现Serializable接口,大多数的集合也应该如此. 但代表活动实体的类, 如线程池(Thread Pool), 一般不应该实现Serializable.

  • Externalizable

实现Externalizable接口以实现对象序列化, 这种序列化方式完全由程序员通过writeExternal()和readExternal()决定存储和恢复对象数据的机制。实现Externalizable接口序列化可以带来一定的性能提升,而且还可以完全自己的自定义序列化规则, 因此只有当默认的序列化形式(Serializable)能够合理地描述对象的逻辑状态时,才能使用默认的序列化形式。

文件操作

  • File

Java使用java.io.File来提供对底层文件的抽象, File能够新建/删除/重命名文件和目录,但不能访问文件内容本身(需要使用IO流).

  • java访问文件内容的4种方法

RandomAccessFile:io,随机读取数据,此种访问速度较慢

FileInputStream:io,文件输入流,此种访问速度较慢

缓冲读取(例如:BufferedReader):io,此种访问速度较块

内存映射(MappedByteBuffer):nio,此种访问速度最快

  • RandomAccessFile

RandomAccessFile与普通的Java I/O流不同的是, 他可以支持随机访问文件, 程序可以直接跳转到文件的任意地方读写数据(因此如果只是访问文件的部分内容,或向已存在的文件追加数据, RandomAccessFile是更好的选择).但RandomAccessFile也有一个局限就是只能读写文件, 不能读写其他IO节点.

  • MappedByteBuffer

FileChannel提供了map方法来把文件影射到内存中(这里的内存指的是虚拟内存,并不是物理内存): MappedByteBuffer map(int mode,long position,long size),该方法可以把文件的从position开始的size大小的区域映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer。但同时有个内存占用的问题就是被MappedByteBuffer打开的文件只有在垃圾收集时才会被关闭,在这之前会一直占用内存。

Scanner

jdk1.5+专门的扫描数据工具类,也可以读取和校验从输入流、文件、字符串、指定源、指定信道为入口的数据。nextline()是通过正则表达式获取每行的内容,RandomAccessFile、BufferedReader是比较每个字符是否是换行符才获取每行的内容。

参考资料

1.Java I/O

jdk-timer、spring-task、quartz的比较

这篇文章将简单介绍目前常用的定时任务框架! Continue reading

小岛经济学-读书笔记

Published on May 10, 2018

java常见的http请求库

Published on May 05, 2018