以下看视频学习的java I/O笔记。
1.File类是表示磁盘上的一个文件或者一个目录。File类没有指定信息怎样从文件读取或者写入,仅仅对文件或者目录的描述。File与平台无关。
2.Java的IO从功能上划分为:输入流和输出流。从结构上划分:字节流和字符流。
输入和输出都是相对于程序来说的,如果从文件到程序,则是输入;从程序到文件,则是输出。
3.字节流的输入、输出的顶层类:InputStream(read方法)、OutputStream(write方法);字符流的输入、输出的顶层类:Reader、Writer。这四个类都是抽象的,有很多的子类实现。
4.字节流是为处理字节而设计,例如对读写二进制很有用。字符流的底层还是字节流。
5.字节流类(Byte Streams):字节流类用于向字节流读写8位二进制的字节。一般地,字节流类主要用于读写诸如图象或声音等的二进制数据。
•字符流类(Character Streams):字符流类用于向字符流读写16位二进制字符。
6.字节流:
InputStream和OutputStream是处理字节流的顶层类,并且都是抽象的,最重要的方法是read和write。
以字节流方式读取一个文件的实现代码:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStream1 {
public static void main(String[] args) throws Exception {
System.out.println("Read stream by byte.");
File file = new File("src/file/file1.txt");
InputStream in = new FileInputStream(file);
byte[] bytes = new byte[100];
String temp;
while (-1 != in.read(bytes, 0, bytes.length)) {
temp = new String(bytes, 0, bytes.length);
System.out.println(temp);
}
in.close();
}
}
以字节流方式写入一个文件的实现代码:
package com.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamByByte1 {
public static void main(String[] args) throws Exception {
File file = new File("src/file/file2.txt");
OutputStream out = new FileOutputStream(file);
String temp = new String("hello world");
out.write(temp.getBytes(), 0, temp.length());
out.flush();
out.close();
}
}
7.过滤流:
在InputStream类和OutputStream类子类中,FilterInputStream和FilterOutputStream过滤流抽象类又派生出DataInputStream和DataOutputStream数据输入输出流类等子类。
过滤流的主要特点:
1.是在输入输出数据的同时能对所传输的数据做指定类型或格式的转换,即可实现对二进制字节数据的理解和编码转换。
2.过滤流在读/写数据的同时可以对数据进行处理,它提供了同步机制,使得某一时刻只有一个线程可以访问一个I/O流,以防止多个线程同时对一个I/O流进行操作所带来的意想不到的结果。
3.类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类。
8.基本的流类
a.FileInputStream和FileOutputStream
节点流,用于从文件中读取或往文件中写入字节流。如果在构造FileOutputStream时,文件已经存在,则覆盖这个文件。
b.BufferedInputStream和BufferedOutputStream
过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。
c.DataInputStream和DataOutputStream
过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。
d.PipedInputStream和PipedOutputStream
管道流,用于线程间的通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有用,必须同时构造管道输入流和管道输出流。
9.预定义设备:为了方便使用计算机的输入输出设备,各种高级语言与操作系统对应,都规定了可用的标准设备(文件)。所谓标准设备(文件),也称为预定义设备(文件),在程序中使用这些设备(文件)时,可以不用专门的打开操作就能简单的应用。一般地,标准输入设备是键盘,标准输出设备是终端显示器,标准错误输出设备也是显示器。
System.in是标准的输入流,是InputStream类,字节流,默认设备为键盘;System.out和System.err都是标准输出流、错误输出流,是PrintStream类,字节流,默认设备是控制台。当然可以使用包装类来进行对字节流进行包装。
System.in的一个例子,从键盘输入一行字符,直到输入的是“byte”一行则退出:
package com.io;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class PredefineStream {
public static void main(String[] args) throws Exception {
BufferedReader bis = new BufferedReader(
new InputStreamReader(System.in));
String str = bis.readLine();
while (!"bye".equals(str)) {
System.out.println(str);
str = bis.readLine();
}
bis.close();
}
}
10.缓冲字节流:通过把内存缓冲区连到输入/输出流扩展一个过滤流类。该缓冲区允许Java对多个字节同时进行输入/输出操作,提高了程序性能。因为缓冲区可用,所以可以跳过、标记和重新设置流。缓冲字节流类是BufferedInputStream 和BufferedOutputStream。PushbackInputStream 也可实现缓冲流。
缓冲输入/输出是一个非常普通的性能优化。Java 的BufferedInputStream 类允许把任何InputStream 类“包装”成缓冲流并使它的性能提高。
11.DataInputStream与DataOutputStream
字节文件流FileInputStream和FileOutputStream只能提供纯字节或字节数组的输入/输出,如果要进行基本数据类型如整数和浮点数的输入/输出。则要用到过滤流类的子类二进制数据文件流DataInputStream和DataOutputStream类。这两个类的对象必须和一个输入类或输出类联系起来,而不能直接用文件名或文件对象建立。
一个例子:
package com.io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class DataOutputStreamByByte1 {
public static void main(String[] args) throws Exception {
OutputStream os = new FileOutputStream(new File("src/file/file2.txt"));
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(1);
dos.writeBoolean(false);
dos.writeDouble(1.2);
dos.flush();
dos.close();
InputStream is = new FileInputStream(new File("src/file/file2.txt"));
DataInputStream dis = new DataInputStream(is);
int a = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println(a + " " + b + " " + d);
dis.close();
}
}
12.字符流
尽管字节流提供了处理任何类型输入/输出操作的足够的功能,它们不能直接操作Unicode字符。Reader和Writer是字符流的顶层类,都是抽象的。由于Java采用16位的Unicode字符,因此需要基于字符的输入/输出操作。这两个类类似于InputStream和OuputStream,也只是提供一些用于字符流的规定,本身不能用来生成对象。
InputStreamReader和OutputStreamWriter用于处理字符流的基本类,用来在字节流和字符流之间搭一座“桥”。这里字节流的编码规范与具体的平台有关,可以在构造流对象时指定规范,也可以使用当前平台的缺省规范。
FileReader类创建了一个可以读取文件内容的Reader类。FileReader继承于InputStreamReader。它最常用的构造方法显示如下
–FileReader(String filePath)
–FileReader(File fileObj)相对应的有FileWriter类。
BufferedReader 通过缓冲输入提高性能。相对应的有个BufferedWriter类。
13. RandomAccessFile随机文件访问类
该类同时实现了DataInput和DataOutput这两个接口,并没有派生于InputStream和OutputStream。
14.序列化
将对象转换为字节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化。
将一个对象保存到永久存储设备上称为持久化。
一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。
序列化(serialization)是把一个对象的状态写入一个字节流的过程。
15.序列化特点
a.当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
b.如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
c.如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
d.如果一个类可以序列化,它的所有子类都可以序列化。
e. 声明成transient的变量不被序列化工具存储。同样,static变量也不被存储。
f. 若某类要完全控制某一对象及其超类型的流格式和内容,则它要实现 Externalizable 接口的 writeExternal 和 readExternal 方法。这些方法必须显式与超类型进行协调以保存其状态。这些方法将代替自定义的 writeObject 和 readObject 方法实现。
g. 反序列化时不会调用对象的任何构造方法,仅仅根据所保存的对象状态信息,在内存中重新构建对象.
16. ObjectInput是反序列化的接口,继承了DataInput接口,实现类有ObjectInputStream类,重要的是readObject方法。相对应的是ObjectOutput接口。
序列化与反序列化代码:
package com.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerializableTest {
public static void main(String[] args) throws Exception {
Student zhangsan = new Student(12, "zhangsan", 1.8);
Student lisi = new Student(15, "lisi", 1.4);
Student wangwu = new Student(13, "wangwu", 1.5);
ObjectOutput oop = new ObjectOutputStream(new FileOutputStream(
new File("src/file/object.txt")));
oop.writeObject(zhangsan);
oop.writeObject(lisi);
oop.writeObject(wangwu);
oop.flush();
oop.close();
ObjectInput oip = new ObjectInputStream(new FileInputStream(new File(
"src/file/object.txt")));
Student a = (Student) oip.readObject();
System.out
.println(a.getAge() + "," + a.getName() + "," + a.getHeight());
oip.close();
}
}
class Student implements Serializable {
private int age;
private transient String name;
private double height;
public Student(int age, String name,double height) {
this.age = age;
this.name = name;
this.height = height;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public double getHeight() {
return height;
}
}
总结:
InputStream和OutputStream:字节流的输入输出。
Reader和Writer:字符流的输入输出
I/O均采用了装饰模式。