Java IO流

字节流、字符流、缓存流、转换流、属性集、序列流、打印流

IO 操作

Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。

IO的分类

根据数据的流向分

  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。

根据数据的类型分

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。

IO流相关类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
IO流
|--字节流
|--InputStream 输入流
|--FileInputStream
|--BufferedInputStream
|--OutputStream 输出流
|--FileOutputStream
|--BufferedOutputStream
|--字符流
|--Reader
|--FileReader 输入流
|--BufferedReader
|--Writer
|--FileWriter 输出流
|--BufferedWriter

字节流

一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。

字节输出流OutputStream

java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。

  • public void close() :关闭此输出流并释放资源。 完成流操作后一定要close
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void write(byte[] b)将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len)
  • public abstract void write(int b) :将指定的字节输出流。

FileOutputStream类:文件输出流

  • public FileOutputStream(File file):创建文件输出流, File文件对象
  • public FileOutputStream(String name): 创建文件输出流, name文件名
    • 没有这个文件,则创建,有则清空数据
  • public FileOutputStream(File file, boolean append)
  • public FileOutputStream(String name, boolean append)
    • append为true 表示追加数据, 为false同上面两个构造方法

例子

1
2
3
4
5
6
7
OutputStream out = new FileOutputStream("./src/Demo11/IO/file.txt");
out.write('t');
out.write('a');
out.write('n');
out.write('\n');
out.write("hello!".getBytes());
out.close();

字节输入流InputStream

java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。

  • public void close() :关闭此输入流并释放资源。 完成流操作后一定要close
  • public abstract int read(): 从输入流读取数据的下一个字节,没读到返回-1。
  • public int read(byte[] b): 从输入流中读取一些字节数,将它们存储到字节数组 b中
    • 返回读取的字节数, 没有读到内容才会返回-1

FileInputStream类: 文件输入流

  • FileInputStream(File file)
  • FileInputStream(String name)
    • 没有这个文件,会抛出FileNotFoundException

例子

1
2
3
4
5
6
7
8
9
InputStream in = new FileInputStream("./src/Demo11/IO/file.txt");
System.out.print((char)in.read());
System.out.print((char)in.read());
byte[] bytes = new byte[5];
int len = 0;
while ((len = in.read(bytes)) != -1) {
System.out.print(new String(bytes, 0, len));
}
in.close();

字符流

字符流专门用于处理文本文件。使用字节流读取文本文件时,遇到中文字符可能不会显示完整的字符。

字符输入流Reader

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。

  • public void close() :关闭此流并释放资源。
  • public int read(): 从输入流读取一个字符, 没读到返回-1。
  • public int read(char[] cbuf)
    • 返回读取的字节数, 没有读到内容才会返回-1

FileReader 类:构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。
  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

字符输出流Writer

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。

  • void write(int c) 写入单个字符。
  • void write(char[] cbuf)写入字符数组。
  • abstract void write(char[] cbuf, int off, int len): off开始索引, len写入字符数
  • void write(String str)写入字符串。
  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • void flush()刷新该流的缓冲。
  • void close() 关闭此流,但要先刷新它。

FileWriter类: 构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

关闭/刷新缓冲区

  • flush :刷新缓冲区,流对象可以继续使用。
    • 缓冲区满了,无需调用flush方法便会自动刷新。
    • 没有刷新缓冲区,无法写入字符到文件中
  • close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了

属性集Properties

java.util.Properties 继承于Hashtable ,来表示一个持久的属性集, 可保存在流中或从流中加载。它使用键值结构存储数据,且键和值都是字符串类型。

  • public Properties() :创建一个空的属性列表。

  • public Object setProperty(String key, String value) : 保存一对属性。

  • public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。

  • public Set<String> stringPropertyNames() :所有键的名称的集合。

与流相关的方法

  • void store(OutputStream out, String comments)将此 Properties 表中的属性列表(键和元素对)写入输出流。

  • void store(Writer writer, String comments)将此 Properties 表中的属性列表(键和元素对)写入输出字符。

  • public void load(InputStream inStream): 从字节输入流中读取键值对。

  • void load(Reader reader)从输入字符流中读取属性列表(键和元素对)。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FileWriter fw = new FileWriter("prop.file");
FileReader fr = new FileReader("prop.file");

Properties prop = new Properties();
prop.setProperty("1", "tan1");
prop.setProperty("2", "tan2");

// 写入到流中
prop.store(fw, "test properties");

// 从流中读取
Properties p2 = new Properties();
p2.load(fr);

for (String key : p2.stringPropertyNames()) {
System.out.println(key + " = " + p2.getProperty(key));
}

缓冲流

缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流。

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

  • public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
  • public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。
  • 字符缓冲流的基本方法与普通字符流调用方式一致, 需要注意的是缓存流的close方法会关闭传入普通字符流

转换流

InputStreamReader类

转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。

它读取字节,并使用指定的字符集将其解码为字符。

  • InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
  • InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。

OutputStreamWriter类

转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。

使用指定的字符集将字符编码为字节。

  • OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
  • OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。

序列化

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

  • public ObjectOutputStream(OutputStream out)
  • public final void writeObject(Object obj)

一个对象要想序列化,必须满足两个条件:

  • 该类必须实现java.io.Serializable 接口
    • Serializable 是一个标记接口
    • 对没有实现该接口的类,进行序列化反序列化会抛出NotSerializableException
  • 该类的所有属性必须是可序列化的。
    • 如果有一个属性不需要可序列化的,则该属性必须使用transient关键字注明是瞬态的。

ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

  • public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
  • public final Object readObject () : 读取一个对象。

反序列化前提

  • 要能找到这个对象的class文件
    • 找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。
  • 序列化之后,class文件不能发生改变
    • 发生改变,则会抛出一个InvalidClassException异常。
    • Serializable 接口给需要序列化的类,提供了一个版本序列号serialVersionUID 用于验证序列化的对象和对应类是否版本匹配。我们可以给它一个固定值,这样就不受该序列号的影响了

例子:序列化集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static void main(String[] args) throws Exception {
// 创建 学生对象
Student student = new Student("老王", "laow");
Student student2 = new Student("老张", "laoz");
Student student3 = new Student("老李", "laol");

ArrayList<Student> arrayList = new ArrayList<>();
arrayList.add(student);
arrayList.add(student2);
arrayList.add(student3);
// 序列化操作
// serializ(arrayList);

// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));
// 读取对象,强转为ArrayList类型
ArrayList<Student> list = (ArrayList<Student>)ois.readObject();

for (int i = 0; i < list.size(); i++ ){
Student s = list.get(i);
System.out.println(s.getName()+"--"+ s.getPwd());
}
}

private static void serializ(ArrayList<Student> arrayList) throws Exception {
// 创建 序列化流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));
// 写出对象
oos.writeObject(arrayList);
// 释放资源
oos.close();
}

打印流

平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

System.out就是PrintStream类型的,只不过它的流向是系统规定的,打印在控制台上。

  • public PrintStream(String fileName): 使用指定的文件名创建一个新的打印流。

例子:改变打印流

1
2
System.setOut(new PrintStream("out.txt"));
System.out.println("hello world"); // 打印到文件中

 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×