Java 的IO

任何编程语言都要和文件打交道,都要有输入输出的操作。

基于此,我们有字节、字符的输入、输出流的概念。

输入输出的概念是相对的,一般我们都是站在编写的程序下的角度看的。

我们还有 字节、字符的概念。

  • 字节:

    计算机存储东西,一般都是基于字节来存储的,也就是我们看到的五彩斑斓的电脑世界(比如说视频、图像、音频啊等等的),他们在内存中,在磁盘中,都是以 字节 的形式来存储的。(或者说是那些二进制数字)

    1字节 = 8位 (1 Byte = 8 bit)

  • 字符:

    就很简单,一个字符就代表一个我们所认知的符号。

    这么说吧,字符串我们还算是比较熟悉的了,字符串就是 很多个字符串在一起,可以看成是很多个字符的序列。

    在 Java 里, 字符用 char 或者 Character 来表示 ,在内存大小里占 2个字节(和他的编码方式有关)。

先了解下编码和解码的概念

编码: 把 字符 转换成 字节的过程。(编成计算机所理解的东西)

解码: 把 字节 转换成 字符的过程。(解成人类所理解的东西)

如果编码和解码的过程,使用的不是一套编码方式,就会出现乱码的现象。

有一些简单的、常见的编码方式:

  • GBK编码: 一个中文占2个字节,一个英文占1个字节。
  • UTF-8编码: 一个中文占3个字节,一个英文占1字节。
  • UTF-16be编码:不管一个中文,还是一个英文,都是占2个字节。

​ (be指的是大端方式: big endian。 相应的有小端方式,le: little endian)

Java 内存的编码方式,使用的就是双字节编码——UTF-16be编码,这样就能让一个中文或英文使用一个 char 来存储了。

Java 中 String 的编码方式: String 的默认编码方式跟平台有关,一般都是 UTF-8编码。

// 将 “中文” 这个字符串, 用 UTF-8 的编码方式,编码成 字节数组。
byte[] bytes = "中文".getBytes("UTF-8");	// 无参的话,默认就是 UTF-8

// 将 字节数组bytes 里的内容,用UTF-8的编码方式,解码成 字符串。
String str = new String(bytes, "UTF-8")

序列化 和 反序列化

趁热打铁,其实序列化和反序列化 与 编码和解码 的概念还是挺像的,但也只是像,他们还是有区别的!

先了解概念:

序列化: 将 对象 转换成字节,方便存储和传输。 (注意是 对象,区别就在这里,序列化只是保存对象的状态)

我们不能对 静态变量 进行序列化,因为序列化保存的 对象的状态,而静态变量是,属于类的状态。

反序列化: 顾名思义,就是序列化的反操作。

Java 中的序列化和反序列化:

必须实现 Serializable 接口(虽然这个接口没有任何方法需要实现),否则就会抛 不支持序列化的异常。

ObjectOutputStream.writeObject(Object obj ) ,进行序列化,将对象写入到文件。

Object obj = ObjectInputStream.readObject( ),进行反序列化,将文件读取到对象中。

transient 关键字:

被 transient 关键字修饰的属性不会被 序列化。

比如 ArrayList 中 存储数据的数组 elementData 就被 transient 修饰,他不能被序列化。

因为他是动态扩容的,并不是所有空间都需要序列化。

可以重写他的序列化 和 反序列化的 方法。

关于字符的 IO

字符流是用到了缓冲区的概念的,而字节流是没有缓冲区的。

我们需要把缓冲区的内容搞出来。(.close( ) 方法前会清空缓冲区, 或者手动调用 .flush( ) 方法来刷新缓冲区)

  • 字符输入流: 抽象类: Reader; 可以用 FileReader 来实现。

  • 字符输出流: 抽象类: Writer; 可以用 FileWriter 来实现。

但是不管是 内存、磁盘、还是网络传输,存储的最小单位都是字节。

我们在程序中打交道的往往是 字符形式的数据。

所以就有 字符 和 字节 转换的需求:

字节流 解码成 字符流:InputStreamReader (读进来的,我们需要用)

字符流 编码成 字节流:OutputStreamWriter (写出去的,计算机需要用)

关于字节的 IO

  • 字节输入流:抽象类:InputStream; 可以用 FileInputStream 来实现。

  • 字节输出流:抽象类:OutputStream; 可以用 FileOutputStream 来实现。

这些类设计,用到了 装饰者模式 这个设计模式。

关于文件

Java 中用 File 类 来表示文件或者目录,但他不表示文件里的内容。

从 Java7 开始, 可以用 Files 和 Paths 类来代替了。