一、缓冲流
File(InputStream、OutputStream、Reader、Writer)流为IO流的入门。
缓冲流也叫高效流,能够高效读写。对基本流对象的增强。
字节缓冲流:BufferedInputStream , BufferedOutputStream
字符缓冲流:BufferedReader BufferedWriter
构造方法
- 字节缓冲流
public BufferedInputStream(InputStream in):创建一个新的缓冲输入流。
public BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流。
2.字符缓冲流
public BufferedReader(Reader in):创建一个新的缓冲输入流。
public BufferedWriter(Writer out):创建一个新的缓冲输出流。
特有方法
BufferReader: public String readLine():读每一行文字。
BufferWriter: public void newLine():自动换行写一行行分隔符,由系统属性定义符号。
System.out.println();
缓冲输入或输出流给基本的输入输出流增加一个缓冲区(数组)提高基本的输入输出流的读取或写的效率。
练习
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class BufferFileCopy {
public static void main(String[] args) throws Exception{
FileReader fr = new FileReader("a.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bw = new BufferedWriter(fw);
String s;
while((s=br.readLine())!=null){ //读取每一行文本,直到为空。
System.out.println(s); //System.out代表屏幕
//bw.write(s,0,s.length());
bw.write(s);
bw.newLine();//自动换行
}
bw.flush(); //将缓冲区的内容写入文件
fr.close();fw.close(); //注意流的关闭顺序
br.close();bw.close();
}
}
二、转换流
编码:按照某种规则,将字符存储到计算机中。
解码:将存储在计算机中的二进制数按照某种规则解析显示出来。
编码:字符(能看懂得)–>字节(看不懂的)
解码:字节(看不懂的)–>字符(能看懂的)
字符编码Character Encoding:就是一套自然语言的字符与二进制数之间的对应规则。
字符集Charset:也叫编码表,是一个系统支持的所有字符的集合,包括国家文字、标点符号、图形符号、数字等。
常见的字符集有:ASCLL字符集、GBK字符集、Unicode字符集。
不同字符集,容易出现编码错误。
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):创建一个指定的字符流。
编码表:生活中的文字和计算机中二进制的对应规则。
GB:是为了显示中文而设计的一套字符集。 Unicode :万国码。
练习
import java.io.*;
public class Test1 {
public static void main(String[] args) throws IOException {
InputStreamReader gbk = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
OutputStreamWriter utf = new OutputStreamWriter(new FileOutputStream("aa.txt"), "utf-8");
int len = 0;
while ((len = gbk.read()) != -1) {
utf.write(len);
}
utf.close();
gbk.close();
}
}
三、序列化
通常情况下 ,当Java程序运行结束时,JVM内存中的相关对象将随之销毁。如果想将对象以某种方式保存下来,在程序下次运行时再恢复该对象,可以通过对象的序列化和反序列化来实现。
Java提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象的存储属性等信息。
反序列化:该字节序列从文件中读取回来,重构对象。
字节-----ObjectInputStream反序列化---->对象
对象-----ObjectOutputStream序列化---->字节
ObjectOutputStream类
序列化流
java.io.ObjectOutputStream 类,将java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法
public ObjectOutputStream(OutputStream out):创建一个指定OutputStream的ObjectOutputStream。
特有的成员方法:
writeObject:将指定对象写入ObjectOutputStream中。
序列化操作
1.对象要想序列化,必须满足两个条件。
*该类必须实现java.io.Serializable接口,Serializable是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException。
*该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient关键字修饰。
注意:
- 用transient修饰的对象变量将不会序列化。
- 用static修饰的类变量实际上属于类,可以序列化到一个对象中,但可能被其他对象改变,所以没有什么意义。
2.写出对象方法
public final void writeObject (Object obj):将指定的对象写出
3.ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in):创建一个指定InputStream的ObjectputStream。
特有的成员方法:
readObject:从 ObjectInputStream 读取对象。对象的类、类的签名和类及所有其超类型的非瞬态和非静态字段的值都将被读取。
反序列化操作1
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法:
public final Object readObject() :读取一个对象。
对于JVM可以反序列化 对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个ClassNotFoundException异常。
反序列化操作2
当反序列化对象,能够找到class文件,但是class文件在序列化对象之后发生了修改,那么序列化操作也会失败,抛出一个InvalidClassException异常。
解决的方法:手动给类添加一个序列号。static final long serialVersionUID
练习
import java.io.*;
class Student implements Serializable {
private static final long serialVersionUID = 1L; //手动给类添加一个序列号。防止反序列化失败
transient int id;//瞬态关键字不能被序列化,为0;
//int id;//这个ID不为0可以序列化
static int age;//待解决
private String name;
String dept;
public Student(int id, String name, int age, String dept) {
this.id = id;
this.name = name;
this.age = age;
this.dept = dept;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + '\'' + ", dept='" + dept + '\'' + ", age='" + age + '\''+ '}';
}
}
public class ObjectStreamTest {
public void saveObj(){
Student stu = new Student(981036, "黎明", 16, "CSD");
try {
FileOutputStream fo = new FileOutputStream("o.ser");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(stu);//将指定对象写入ObjectOutputStream中。
so.close();
}catch(Exception e){
System.err.println(e);
}
}
public void readObj() throws Exception{
Student stu;
FileInputStream fi = new FileInputStream("o.ser");
ObjectInputStream si = new ObjectInputStream(fi);
stu = (Student)si.readObject(); //读取对象
si.close();
System.out.println(stu);
}
public static void main(String[] args)throws Exception {
ObjectStreamTest os = new ObjectStreamTest();
os.saveObj();
os.readObj();
}
}
四、打印流
PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
特点
- 只负责数据的输出。
- 不抛出IOException异常。
- 特有方法:print、println。
PrintStream extends OutputStream.
注意:
- 如果使用继承自父类的write方法,查询编码表。
- print/println。数据原样输出。
练习
1.可以改变输出语句的目的地(打印流的流向)
2.输出语句,默认在控制台输出
3.使用System.setOut(PrintStream out) 重新分配标准流
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class test {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("我是在控制台输出");
PrintStream ps = new PrintStream("a.txt");
System.setOut(ps);//把输出语句的目的地改变为打印流的目的地
System.out.println("我在打印流的目的地中输出");
ps.close();
}
}