IO框架
课程目标
- 流的概念
- 流的分类
- 字节流
- 编码方式
- 字符流
- File流
什么是流
概念:内存与储存设备之间传输数据的通道
流的分类
按方向【重点】:
输入流:将<储存设备>中的内容读入到<内存>中。
输出流:将<内存>的内容写入到<储存设备>中。
按单位:
字节流:以字节为单位,可以读写所有数据。
字符流:以字符为单位,只能读写文本数据。
按功能:
节点流:具有实际传输数据的读写功能。
过滤流:在节点流的基础上增强功能。
字节流
字节流的父类(抽象类):
InputStream:字节输入流
OutputStream:字节输出流
FileInptuStream的使用
FileInputStream:
public int read (byte[] b) // 从流中读取多个字节,将读到内容输入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回 - 1.
FileOutputStream:
public viod write(byte[] b) //一次写多个字节,将b组的所有字节,写入输入流
package IO.IO1;
import java.io.FileInputStream;
/**
* 演示FileInputStream的使用
* 文件字节输入流
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
//1创建FileInputStream,并指定文件路径
FileInputStream fis = new FileInputStream("d:\\aaa.txt");
// //2读取文件
// //2.1单个字节读取
// //fis.read()
// int data = 0;
// while((data = fis.read())!=-1){
// System.out.println((char) data);
// }
//2.2一次读取多个字节
//
// byte[] buf = new byte[3];
//
// int count = fis.read(buf);
// System.out.println(new String(buf));
// System.out.println(count);
//
// int count2 = fis.read(buf);
// System.out.println(new String(buf));
// System.out.println(count2);
//
// int count3 = fis.read(buf);
// System.out.println(new String(buf,0,count3));
// System.out.println(count3);
byte[] buf = new byte[3];
int count = 0;
while((count = fis.read(buf))!=-1){
System.out.println(new java.lang.String(buf,0,count));
}
//3关闭
fis.close();
System.out.println("执行完毕");
}
}
FileOutStream的使用
package IO.IO1;
import java.io.FileOutputStream;
public class Demo02 {
public static void main(String[] args) throws Exception{
//1创建文件字节输出流对象
//FileOutputStream fos = new FileOutputStream("d:\\bbb.txt");
//会覆盖
FileOutputStream fos = new FileOutputStream("d:\\bbb.txt",true);
//不会覆盖
// //2输入文件
// fos.write(97);
// fos.write('b');
// fos.write('c');
String string = "helloworld";
fos.write(string.getBytes());
//3关闭
fos.close();
System.out.println("执行完毕");
}
}
字节流复制文件
package IO.IO1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Demo03 {
public static void main(String[] args) throws Exception {
//1创建流
FileInputStream fis = new FileInputStream("d:\\001.jpg");
//1.2文件字节输出流
FileOutputStream fos = new FileOutputStream("d:\\002.jpg");
//2一边读,一边写
byte[] buf = new byte[1024];//字节数组
int count = 0;
while((count = fis.read(buf))!=-1){
fos.write(buf,0,count);//指定的数组中偏移的个数 指定的数组的下标 存储数据的长度
}
//3关闭
fis.close();
fos.close();
System.out.println("执行完毕");
}
}
字节缓冲流
缓冲流:BufferedInputStream/BufferedOutputStream
提高IO效率,减少访问磁盘的次数;
数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close。
BufferedInputStream的使用
package IO.IO1;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 使用字节缓冲流读取
*/
public class Demo04 {
public static void main(String[] args) throws Exception{
//1创建BufferedInputStream
FileInputStream fis = new FileInputStream("d:\\aaa.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
//2读取
// int data = 0;
// while((data = bis.read())!=-1){
// System.out.println((char)data);
// }
//2.1自创缓冲区
byte[] buf = new byte[1024];
int count = 0;
while((count = bis.read(buf))!=-1){
System.out.println(new String(buf,0,count));
}
//3关闭
bis.close();
}
}
BufferedOutputStream的使用
package IO.IO1;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Demo05 {
public static void main(String[] args) throws Exception{
//1创建字节输出缓冲流
FileOutputStream fos = new FileOutputStream("d:\\buffer.txt");
BufferedOutputStream bos =new BufferedOutputStream(fos);
//2写入文件
for(int i = 0;i<10;i++){
bos.write("helloworld\n".getBytes());//先写入缓冲区,大小8k
bos.flush();//刷新到硬盘
}
//3关闭(内部调用flush方法)
bos.close();
System.out.println("执行完毕");
}
}
对象流
对象流:ObjectOutputStream/ObjectInputStream
增强了缓冲区功能
增强了读写8种基本类型和字符串功能
增强了读写对象的功能:
readObject() 从流中读取一个对象
writeObject(Object obj) 向流中写入一个对象
使用流传输对象的过程成为序列化,反序列化。
序列化
package IO.IO1;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
/**
* 使用ObjectOutputStream实现对象的序列化
*/
public class Demo06 {
public static void main(String[] args) throws Exception{
//1创建对象六
FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2序列化(写入操作)
Student zhangsan = new Student("张三",20);
oos.writeObject(zhangsan);
//3关闭
oos.close();
System.out.println("序列化完毕");
}
}
异常:
NotSerializableException
学生类无法实例化
可以通过
implements Serializable
继承Serializable使学生类可以实例化
反序列化
package IO.IO1;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
/**
* 使用ObjectInputStream实现啊反序列化(读取重构成对象)
*/
public class Demo07 {
public static void main(String[] args) throws Exception{
//1创建对象流
FileInputStream fis = new FileInputStream("d:\\stu.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
//2读取文件(反序列化)
Student s = (Student)ois.readObject();
//3关闭
ois.close();
System.out.println("执行完毕");
System.out.println(s.toString());
}
}
序列化和反序列化注意事项
注意事项:
(1)序列化类必须要实现Serializable接口
(2)序列化类中对象属性也要实现Serializable接口
(3)序列化版本号ID,保证序列化的类和反序列化的类使同一个类
private static final long serialVersionUID = 1021110L;
异常:
InvalidClassException
类的版本号不同
UID改为异常提示的
IO.IO1.Student; local class incompatible: stream classdesc serialVersionUID = -2773328724821145463
private static final long serialVersionUID = -2773328724821145463L;
(4)使用transient(瞬间的)修饰属性,这个属性不能序列化
transient private int age;
(5)静态属性不能序列化
(6)序列化多个对象
序列化(写入操作)
Student zhangsan = new Student("张三",20);
Student lisi = new Student("李四",20);
oos.writeObject(zhangsan);
oos.writeObject(lisi);
反序列化
Student s = (Student)ois.readObject();
Student s2 = (Student)ois.readObject();
ois.close();
System.out.println("执行完毕");
System.out.println(s.toString());
System.out.println(s2.toString());
这样比较麻烦
改进
序列化
Student zhangsan = new Student("张三",20);
Student lisi = new Student("李四",20);
ArrayList<Student> list = new ArrayList<>();
list.add(zhangsan);
list.add(lisi);
反序列化
ArrayList<Student> list =(ArrayList<Student>)ois.readObject();
ois.close();
System.out.println("执行完毕");
System.out.println(list.toString());
字符编码
ISO-8859-1 收录除ASCII外,还包括修,希腊语,台语,阿拉伯语,希伯来语对应的文字符号
UTF-8 针对Unicode码表的可变长度字符编码
GB2312 简体中文
GBK 简体中文,扩充
BIG5 台湾,繁体中文
当编码方式和解码方式不一致时,会出现乱码。
字符流抽象类
字符流的父类(抽象类):
Reader:字符输入流
public int read(){}
public int read(char[] c){}
public int read(char[] b,int off,int len){}
Writer:字符输出流
public void write(int n){}
public void write(String str){}
public void write(char[] c){}
//UTF-8 12个字节4个汉字3个字节一个汉字,而这里是一个字节一个字节读,所以会乱码
文件字符流
FileReader:
public int read(char[] c)
从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回 - 1。
FileWriter:
public void write(String str)
一次写多个字符,将b数组中所有字符,写入输出流。
package IO.IO2;
import java.io.FileReader;
public class Demo02 {
public static void main(String[] args) throws Exception{
//1创建FileReader 文件字符输入流
FileReader fr = new FileReader("d:\\hello.txt");
//2读取
//2.1单个字符读取
// int data = 0;
// while((data = fr.read())!=-1){//读取一个字符
// System.out.print((char)data);
// }
char[] buf = new char[1024];
int count = 0;
while((count = fr.read(buf))!=-1){
System.out.println(new java.lang.String(buf,0,count));
}
//3关闭
fr.close();
}
}
FileWriter的使用
package IO.IO2;
import java.io.FileWriter;
public class Demo03 {
public static void main(String[] args) throws Exception{
//1.创建FileWriter对象
FileWriter fw = new FileWriter("d:\\write.txt");
//2.写入
for (int i = 0;i<10;i++){
fw.write("java是世界上最好的语言\r\n");
fw.flush();
}
fw.close();
System.out.println("执行完毕");
}
}
字符流复制文件
使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件
因为FileReader是读取字符,会把二进制(1011011)数读成乱码
package IO.IO2;
import java.io.FileReader;
import java.io.FileWriter;
/**
* 使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件
*/
public class Demo04 {
public static void main(String[] args) throws Exception{
//1创建FileReader FileWriter
FileReader fr = new FileReader("d:\\write.txt");
FileWriter fw = new FileWriter("d:\\write2.txt");
//2读写
int data = 0;
while((data = fr.read())!=-1){
fw.write(data);//fr读取write,fw写进write2
fw.flush();
}
//3关闭
fr.close();
fw.close();
System.out.println("复制完毕");
}
}