0%

Java筑基-:(07)Java IO在Android中应用基础篇

数据流是一组有序、有起点和终点的字节的数据序列,包括输入流和输出流。

一、IO 简介

流序列中的数据既可以是未经过加工的原始二进制数据,也可以是经过一定编码处理后符合某种格式规定的特定数据。在Java 中流分为 2 种: 字节流 和 字符流

  • 字节流: 数据流中最小的数据单位是字节
  • 字符流:数据流中最小的数据单元是字符,Java 中的字符是 Unicode 编码,一个字符占用 2 个字节

java.io 中最重要的就是 5 个类和一个接口:

  • 5个类指: File、字节流中的 OutputStream 和 InputStream、字符流中的 Writer 和 Reader ;

  • 一个接口是指 : Serializable

在 Android 中,文本文件/XML 等这些都是用 字符流来读写;而如 RAR、图片等非文本,则用字节流来读写。

二、Java IO 中的装饰模式

以一段容易让人费解的代码开始:

1
2
3
4
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(
new File(file))));

这个代码看起来很乱,多重嵌套,其实要理解 IO ,也不难,难的是要更优地去使用 IO 。接下来抽丝剥茧地解释一下上述代码:

  1. new File() 就是创建一个 File 文件,这个没什么好说的

  2. FileOutputStream 这层就是将 File 转为字节流

  3. BufferedOutputStream 就是用来提升速度的,减少对磁头的调用,如果没有它,就会一个一个字节地去访问磁盘;有了它之后,就是一块一块地访问

  4. 而使用 DataOutputStream 就是保持数据的格式

我们在日常使用的时候,一般都要是优先考虑 DataOutputStream ,然后交给 BufferedOutputStream 提升效率。上面的例子就是典型的用法。

要理解输入输出流,要把自己当做电脑的 内存,站在内存的角度思考,这样 OutputStream 就是写出到磁盘上了,InputStream 就是读入到内存了。

为了能更好地理解,我们这里写一个 Demo:

1
2
3
4
5
6
7
8
9
10
11
private static void testDataOutputStream() throws Exception{
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
new FileOutputStream(new File("C:\\Users\\panda\\IdeaProjects\\JavaDemo\\src\\testtxt\\out.txt"))
));
out.writeInt(1);
out.writeBoolean(false);
out.writeByte((byte)0x41);
out.writeLong((long)0x98765432);

out.close();
}

我们能看到上述代码往文件中写入了东西,但是直接打开看起来是乱码的,这只是编码的问题,使用正确的编码就不会有问题。

还有一点要注意,使用 DataOutputStream 写入之后,通过 DataIntputStream 读出来的时候,需要保证顺序,比如上述例子里面先写入 int ,后写入 boolean ,读的时候也要先读 int 后读 boolean ,否则会错乱

序列化的时候,大量使用这个 IO 操作。

三、装饰器模式

在上述代码中,我们使用 FileOutputStream 也能满足需求,但是为了磁盘好我们又包装了 BufferedOutputStream ,此时也已经能用了,但是为了数据格式,我们又加了 DataOutputStream 。

这种整个一层一层封装就是我们常见的装饰模式,如果要对装饰模式理解深刻一点的话,可以用视频中老师举的例子: 人本身就是一个类(类似Android 中的 Context),但是人一般都穿内衣(),而内衣之外,一般都会穿日常衣服装饰自己。整个装饰器模式的结构如下图所示:

四、字节流与字符流的区别

在开发中到底使用字节流好还是使用字符流好呢?

首先,在硬盘上保存文件或者进行传输的时候都是以字节的形式进行的,包括图片也是按字节完成。字符只有到了内存中才会形成。所以,如果要使用 Java 程序实现拷贝功能的话,应该选用字节流进行操作,并且采用边读边写的方式(节省内存)。

五、字节流与字符流的转换

虽然 Java 支持字节流和字符流,但是有时候需要在二者之间进行转换, InputStreamReader 和 OutputStream 这 2 个类是字节流和字符流之间相互转换的类。

5.1 InputStreamReader

用于将字节流的字节码转成字符,其中一个构造 方法:

1
2
//用默认字符集创建一个 InputStreamReader 对象
InputStreamReader(InputStream in)

5.2 OutputStreamWriter

用于将写入的字符转成字节后写入一个字节流,其中一个构造方法:

1
2
//用默认字符集创建一个 OutputStreamWriter
OutputStreamWriter(OutputStream out)

5.3 BufferedWriter 和 BufferedReader

为了频繁转换字节流和字符流,对以上2个类进行了封装, 即 BufferedWriter类封装了OutputStreamWriter类;BufferedReader类封装了InputStreamReader类;示例代码如下:

1
2
3
4
5
6
7
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader in= new BufferedReader(new InputStreamReader(System.in);

//下面的语句可以从控制台读取一行字符串
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String line=in.readLine();

谢谢你的鼓励