目录
面试题
IO流对象分为那些
按功能分:输入流与输出流
按类型分:字节流与字符流
字节流:字节流按8bit传输,即以字节为单位输入输出
字符流:以字符为单位输入输出
按内存地址分:节点流与过滤流
节点流:从特定的地方读写流,例如磁盘或一块内存区域
过滤流:使用节点流作为输入或输出
常用流介绍
字节输入流:InputStream 抽象类
FileInputStream 文件字节输入流
BufferedInputStream 缓冲字节输入流
DataInputStream 数据字节输入流
ObjectInputStream 对象字节输入流[序列化流]
ByteArrayInputStream 字节数组输入流
字节输出流: OutputStream 抽象类
FileOutputStream 文件字节输出流
BufferedOutputStream 缓冲字节输出流
DataOutputStream 数据字节输出流
ObjectOutputStream 对象字节输出流[反序列化流]
ByteArrayOutputStream 字节数组输出流
PrintStream 打印输出流[打印至控制台]
字符输入流: Reader 抽象类
InputStreamReader 字节输入流转换为字符输入流
BufferedReader 字符缓冲输入流
FileReader 文件字符输入流
字符输出流: Writer 抽象类
OutputStreamWriter 字符输出流转换为字节输出流
BufferedWirter 字符缓冲输出流
FileWriter 文件字符输出流
FileInputStream & FileOutputStream(节点流)
节点流: 从特定的地方读写的流,例如磁盘或一块内存区域
FileInputStream : 输入流,操作的是字节,又叫字节流
FileOutputStrean: 输出流, 操作的是字节,又叫字节流
按字节读,读取效率低
作为编码时,字节没有符号位,8位都是数据位,其范围在0-255
byte数据类型范围 -128-127
因此在把数据读出强转为byte类型时,会存在溢出
一个中文占三个字节,采用utf-8编码
FileInputStream 读
对象.read() 读取一个字节int类
对象.read(byte数组) 读取数组长度的字节,返回读取到的字节长度
public class Demo1FileInputStream {
public static void main(String[] args) {
//文件的读写,离不开File对象
File file=new File("C:\\Users\\LY\\Desktop\\heoll.txt");
FileInputStream in=null;
try {
in=new FileInputStream(file);//输入流 按字节读、单位是byte
int i = in.read();
System.out.println("read: "+i);//读出的是字符
// 可能出现的错误 要么抛出、要么捕获
byte[] bs=new byte[3];
in.read(bs);
System.out.println(Arrays.toString(bs));
//[50, 51, 52]
byte[] bs1=new byte[30];
in.read(bs1,5,20);
System.out.println(Arrays.toString(bs1));
//[0, 0, 0, 0, 0, 53, 13, 10, -27, -113, -111, -25, -108, -97, -24, -65, -121, 13, 10, 103, 100, 99, 97, 115, 0, 0, 0, 0, 0, 0]
//判断文件是否到末尾
int i1 = in.read();//读取内容为-1.就表示读取到末尾
System.out.println(i1);//-1
//字节数组转字符串
System.out.println(new String(bs));//234
System.out.println(new String(bs1));//空格与换行
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();//关闭流
//可能出现的错误 要么抛出、要么捕获
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileOutputStrean 写
对象.write()
对象.write(byte数组)
public static void main(String[] args) throws IOException {
//创建对象
//从文件开始位置开始写入
FileOutputStream fos=new FileOutputStream("C:\\Users\\LY\\Desktop\\heoll.txt");
//从文件末尾位置开始写入
FileOutputStream fos1=new FileOutputStream("C:\\Users\\LY\\Desktop\\a.txt",true);
//指定写入的文件不存在,输出流会先创建文件
//写内容
//按字节写 一个字节
fos1.write(65);//字母A
fos1.write(66);//字母B
fos1.write(67);//字母C
//批量写
byte[] bs="疑是地上霜".getBytes(StandardCharsets.UTF_8);
fos1.write(bs);
byte[] bs1="举头望明月".getBytes(StandardCharsets.UTF_8);
fos1.write(bs1,0,6);//一个中文三个字节
fos1.close();
fos.close();
}
文件复制
public class Demo4FileCopy {
public static void main(String[] args) throws IOException {
//copy("C:\\Users\\LY\\Desktop\\a.txt","C:\\Users\\LY\\Desktop\\b.txt");
//copy1("C:\\Users\\LY\\Desktop\\资料整理\\雄狮少年.pptx","C:\\Users\\LY\\Desktop\\资料整理\\XXXX.pptx");
copy1("C:\\Users\\LY\\Desktop\\a","C:\\Users\\LY\\Desktop\\b");
}
public static void copy(String a,String b) throws IOException {
FileInputStream in=new FileInputStream(a);
FileOutputStream out=new FileOutputStream(b,true);
int k;
while ((k=in.read())!=-1){
System.out.print(k+" ");
out.write(k);
}
in.close();
out.close();
}
public static void copy1(String a,String b) throws IOException {
FileInputStream in=new FileInputStream(a);
FileOutputStream out=new FileOutputStream(b,true);
byte[] n=new byte[1000];
int k=0;
while (true){
k=in.read(n);
if(k<n.length)
break;
else {
out.write(n);
}
}
byte[] n1=new byte[k];
out.write(n1);
in.close();
out.close();
}
}
BufferedInputStream&BufferedOutputStream (过滤流)
使用节点流作为输入或输出
过滤流是使用一个已经存在的输入流或输出流进行创建的
BufferedInputStream
//BufferedInputStream:按字节读取,带缓冲区的输入流,读取效率高于FileInputStream
//创建对象的时候,需先创建字节流FileInputStream
public class Demo5BufferedInputStream {
public static void main(String[] args) {
FileInputStream fis=null;
BufferedInputStream bis=null;
try {
fis=new FileInputStream("C:\\Users\\LY\\Desktop\\资料整理\\雄狮少年.pptx");
//对象创建:通过字节流创建出带缓冲的输入流
bis=new BufferedInputStream(fis);
int read=bis.read();
byte[] bs=new byte[1024];//1024字节,就是1k
int read1=bis.read();
if(read1==-1){
System.out.println("末尾");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();//先关小的
bis.close();//再关大的
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BufferedOutputStream
//BufferedOutputStream:按字节读取,带缓冲区的输入流,读取效率高于FileOutputStream
//创建对象的时候,需先创建字节流FileOutputStream
//写入到缓冲区,到一定容量则自动写入文件
public class Demo6BufferedOutputStream {
public static void main(String[] args) throws IOException {
//创建对象
FileOutputStream f=new FileOutputStream("C:\\Users\\LY\\Desktop\\aa.txt",true);//追加
BufferedOutputStream bos=new BufferedOutputStream(f);
//写入数据
String str="fwfgeg dwfwff dwfwfs ferff";
bos.write(65);//写入到缓冲区
bos.write(str.getBytes(StandardCharsets.UTF_8));
bos.flush();//手动刷新,把缓存区的数据,写入到文件中
bos.close();//关闭流时,会先把缓冲区的数据写入文件即自动调用刷新机制,再关闭流
f.close();
}
}
DatainputStream & DataoutputStream
DataOutputStream & DataInputStream是对流功能的扩展,可以更方便读取int ,long ,char等类型的数据
DataOutputStream,对基本的输出流功能进行扩展,提供了基本数据类型的输出方法
DataInputStream,对基本的输入流功能的扩展,它提供了基本类型的输入方法
写入文件之后,如果用软件打开,会被继续为字符串
//DataOutputStream 按数据进行读
//DataInputStream 按数据进行读
public class Demo7DataOutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream out=new FileOutputStream("C:\\Users\\LY\\Desktop\\aa.");
DataOutputStream dos=new DataOutputStream(out);
dos.writeInt(100);
dos.writeDouble(10.8);
dos.writeChar('A');
dos.writeUTF("中国你好");
dos.close();
//DataOutputStream写的顺序对应 与DataInputStream读取的顺序保持一致
//java.io.EOFException 读的顺序与写的顺序不一致,可能会抛异常
//数据流中写入数据时的顺序和读取时的顺序不一致
FileInputStream in=new FileInputStream("C:\\Users\\LY\\Desktop\\aa.");
DataInputStream ins=new DataInputStream(in);
System.out.println(ins.readInt());
System.out.println(ins.readDouble());
System.out.println(ins.readChar());
System.out.println(ins.readUTF());
ins.close();
}
}
InputStreamReader & OutputStreamWriter
提供字符的处理,一次处理一个字符(unicode)
字符的底层仍然是基本的字节流
InputStreamReader : 完成byte流解析为char流,按照编码解析
OutputStreamWriter:提供char流到字节,按照编码处理
//写字符/字符串,取char\char[]
//字符处理流
public class Demo8OutputStreamWriter {
public static void main(String[] args) throws IOException {
//创建对象
FileOutputStream out= new FileOutputStream("C:\\Users\\LY\\Desktop\\bb.txt");
OutputStreamWriter osw=new OutputStreamWriter(out);
osw.write("清明时间雨纷纷,\n");
osw.write("路上行人欲断魂。\n");
osw.write("作者:XXX");
osw.write('A');
osw.write("这是一个首好诗".toCharArray());//写入缓存区
// osw.flush();
osw.close();//关之前先刷新,再关
FileInputStream in=new FileInputStream("C:\\Users\\LY\\Desktop\\bb.txt");
InputStreamReader irs=new InputStreamReader(in);
char[] cd=new char[1000];
int read=irs.read(cd);
//去除多余的空格
char[] cd1=new char[read];
System.arraycopy(cd,0,cd1,0,read);
//将char[]转换为String类型 String.valueOf();
System.out.println(String.valueOf(cd1));
//trim()去掉前后多余的空格
System.out.println(String.valueOf(cd).trim());
//表示已到文件末尾
System.out.println(irs.read());//-1 表示已到文件末尾
irs.close();
}
}
BufferedReader & BufferedWriter
BufferReader & BufferWriter,更方便处理字符
//BufferedWriter
//BufferedReader
//带缓冲冲区的字符处理流,提供一行一行读取
//java.io.FileNotFoundException
//FileInputStream 给路径为绝对路径
public class Demo9BufferedWriter {
public static void main(String[] args) throws IOException {
//盘符不分大小写
// FileInputStream in=new FileInputStream("E:\\IDEA_DATA\\javadata1\\javadata_one\\javase\\src\\day6\\Demo4FileCopy.java");
// InputStreamReader isr=new InputStreamReader(in);
// BufferedReader br = new BufferedReader(isr);
//
// //br.readLine() 返回值为null 表示读到文件末尾
// //br.readLine() 读取的是一行的内容
// String s;
// while ((s=br.readLine())!=null){
// System.out.println(s);
// }
// br.close();
// isr.close();
// in.close();
copy("E:\\IDEA_DATA\\javadata1\\javadata_one\\javase\\src\\day6\\Demo4FileCopy.java","C:\\Users\\LY\\Desktop\\cc.txt");
}
public static void copy(String s1,String s2) throws IOException {
FileInputStream in=new FileInputStream(s1); //相对路径
InputStreamReader isr=new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
FileOutputStream out=new FileOutputStream(s2);
OutputStreamWriter otr=new OutputStreamWriter(out);
BufferedWriter wr=new BufferedWriter(otr);
String s;
while ((s=br.readLine())!=null){
wr.write(s);
wr.newLine();//需要手动换行
}
wr.close();
br.close();
}
}
对象序列化[ObjectInputStream&ObjectOutputStream]
将Object转换为byte序列,就是序列化,反之将byte序列转换为Object就是反序列化
对象序列化的目的,是为了将对象,以byte流的方式存储
使用writeObject(Object)/readObject()进行序列化和反序列化
ObjectInputStream ois ;
ois.readObject();
ObjectOutputStream oos ;
oos.writeObject(obj);
//ObjectInputStream 从文件中读取出对象
//ObjectOutputStream 把对象写入文件中
public class Demo10ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//写入对象
File f=new File("E:\\IDEA_DATA\\javadata1\\javadata_one\\javase\\src\\day6\\Dobj.temp");
/*
FileOutputStream fos=new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
String str="hello";
Integer i1=100;
Date d=new Date();
oos.writeUTF(str);
oos.writeInt(i1);
oos.writeObject(d);
oos.flush();
oos.close();
*/
//读对象
FileInputStream fis=new FileInputStream(f);
ObjectInputStream ois=new ObjectInputStream(fis);
//读注意顺序
//java.lang.OptionalDataException
System.out.println(ois.readUTF());
System.out.println(ois.readInt());
Object o=ois.readObject();
System.out.println(o);//取出的是一个object变量
//System.out.println(o.getTime()); 无法调用Date中的方法
if(o instanceof Date){
Date d=(Date) o;
System.out.println(d.getTime());
}
}
}
Serializable接口
Serializable是序列化接口,对象必须实现序列化接口,才能进行序列化,否则抛出异常
java的API中的类,大部分都实现了Serializable接口
//对象序列化,再反序列化
//java.io.NotSerializableException 不可序列化
public class Demo11ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化
//java.io.InvalidClassException
File f=new File("E:\\IDEA_DATA\\javadata1\\javadata_one\\javase\\src\\day6\\stu.temp");
/*FileOutputStream out=new FileOutputStream(f);
ObjectOutputStream oos=new ObjectOutputStream(out);
Student student=new Student(10,100,"小红","1001");
oos.writeObject(student);
oos.flush();
oos.close();*/
//反序列化
FileInputStream in=new FileInputStream(f);
ObjectInputStream ios=new ObjectInputStream(in);
Object b=ios.readObject();
if(b instanceof Student){
Student s=(Student) b;
System.out.println(s.toString());
}
ios.close();
}
}
//java.io.NotSerializableException 不可序列化
//要求需要将对象序列化至文件中,则需要将类实现序列化接口即implements java.io.Serializable
//实现可序列化接口 java.io.Serializable
class Student implements java.io.Serializable{
int age;
double money;
String name;
String id;
public Student(int age, double money, String name, String id) {
this.age = age;
this.money = money;
this.name = name;
this.id = id;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", money=" + money +
", name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}
面试题
对象序列化是什么, 用在什么声明场景
java的对象序列化,是为了保存各种对象在内存中的状态,并且保存的对象可通过反序列化再读出来,但被序列化的对象要求必须实现java.io.Serializable接口
例如,通过操作对象的流(ObjectInputStream与ObjectOutputStream),可以从文件中把数据读出来,或者将对象写入文件中
使用场景:
把内存中对象的状态保存到文件中或者数据库中;
网络上(Socket)传输对象的时候
想通过RMI(远程方法调用)传输对象的时候
transient关键字
transien,是java中的关键字,被其修饰的成员变量不会被序列化
private transient Integer brId;
import java.io.*;
//对象序列化,再反序列化
//java.io.NotSerializableException 不可序列化
//transient 透明的,一个关键字,被transient修饰成员变量。在对象被序列化时,不会把该变量的数据值保存在文件中
public class Demo11ObjectInputStream2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化
//java.io.InvalidClassException
File f=new File("E:\\IDEA_DATA\\javadata1\\javadata_one\\javase\\src\\day6\\stu2.temp");
/*FileOutputStream out=new FileOutputStream(f);
ObjectOutputStream oos=new ObjectOutputStream(out);
Student2 student=new Student2(10,100,"小红","1001");
oos.writeObject(student);
oos.flush();
oos.close();*/
//反序列化
FileInputStream in=new FileInputStream(f);
ObjectInputStream ios=new ObjectInputStream(in);
Object b=ios.readObject();
if(b instanceof Student2){
Student2 s=(Student2) b;
System.out.println(s.toString());
//Student{age=10, money=100.0, name='null', id='null'}
}
ios.close();
}
}
//java.io.NotSerializableException 不可序列化
//要求需要将对象序列化至文件中,则需要将类实现序列化接口即implements java.io.Serializable
//实现可序列化接口 java.io.Serializable
class Student2 implements Serializable{
int age;
double money;
transient String name;
transient String id;
//transient 透明的,一个关键字,被transient修饰成员变量。在对象被序列化时,不会把该变量的数据值保存在文件中
public Student2(int age, double money, String name, String id) {
this.age = age;
this.money = money;
this.name = name;
this.id = id;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", money=" + money +
", name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}