IO
-
概述
(1)如果对于File对象来说,输入输出流只能针对文件,不能针对目录
(2)IO操作不仅仅是针对文件,还可以从网络中输入输出
(3)输入输出的参照物是当前程序 -
IO的分类
(1)按方向
输入流(InputStream):将数据从某个源流向程序中
输出流(OutputStream):将数据从程序往外发送到某个目的地
(2)按操作数据的单位
字节流:适用于任何类型的文件,但如果是纯文本文件用字符流更快
字符流:只能用于读/写纯文本数据(内容全部是字符),纯文本文件:.txt,.html,.xml,.properties等是纯文本文件
(3)按功能角色
节点流:和某个文件关联,如文件流…
处理流:在节点流的基础上加其它的处理功能的,例如:缓冲流,序列化,反序列化… -
IO流有四大抽象的父类/基类/超类
(1)InputStream:字节输入流
(2)OutputStream:字节输出流
(3)Reader:字符输入流
(4)Writer:字符输出流
Reader系列:
(1)int read():读取一个字符,返回该字符的Unicode编码
(2)int read(char[] c):读取多个字符,读取的字符放到c数组中,从c的[0]开始存储,最多读取c.length个,返回实际本次读取的字符个数
(3)int read(char[] c,int off,int len):读取多个字符,读取的字符放到c数组中,从c的[off]开始存储,最多读取len个 ,返回实际本次读取的字符个数
如果流中没数据可读,以上方法返回-1
Writer系列:
(1)void write (char c):写单个字符
(2)void write(char[] c):把单个字符数组的内容写出去
(3)void write(char[] c,int off,int len):从c[off]开始,把len个字符写出去
(4)void write(String str):把str的内容写出去
(5)void write(String str,int off,int len):把str从[off]开始将len个字符写出去
(6)void close():关闭
(7)void flush():刷新
InputStream系列
(1)int read():一次读取一个字节,返回本次读取的字节的值
(2)int read(byte[] b):一次读取多个字节,返回本次实际读取字节数,读取的字节存到b数组中,从[0]开始存储,一次最多存储b.length个字节
(3)int read(byte[] b,int off,int len):一次读取多个字节,返回本次实际读取字节数,读取的字节存到b数组中,从[off]开始存储,一次最多存储len个字节
如果流中没数据可读,以上方法返回-1
OutputStream系列
(1)void write(int b):写一个字节
(2)void write(byte[] b):写一个字节数组的所有
(3)void write(byte[] b,int off,int len):从b[off]开始,把len个字符写出去
(4)void close()
(5)void flush():刷新 -
缓冲IO流
是处理流,负责在其他IO流基础上增加缓冲功能,默认的缓冲区大小8192字节/字符
BufferedReader只能给Reader增加缓冲功能
BufferedWriter只能给Writer…
BufferedInputStream-----InputStream
BufferedOutputStream------OutputStream
BufferedReader在Reader基础上增加了:String readLine()读取一行,达到流的结尾,返回null
BufferedWriter在Writer的基础上增加了:void newLine()写换行符//部分代码 FileReader fr = new FileReader("1.txt"); BufferedReader br=new BufferedReader(fr); FileWriter fw=new FileWriter("2.txt"); BufferedWriter bw=new BufferedWriter(fw); String str; while((str=br.readLine())!=null){ bw.write(str); } bw.close(); fw.close(); br.close(); fr.close();
-
转换流
解码:将字节流转换为字符流
InputStreamReader//解码 字节--字符 FileInputStream fis=new FileInputStream("1.txt"); InputStreamReader isr=new InputStreamReader(fis,"GBK"); char[] arr=new char[10]; int len=isr.read(arr); System.out.println(new String(arr,0,len)); isr.close(); fis.close();
编码:将字符流转化为字节流
OutputStreamReader
//编码 字符---字节
String str="亮";
FileOutputStream fos=new FileOutputStream("1.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"GBK");
osw.write(str);
osw.close();
fos.close();
- 数据IO流
DataOutputStream在OutputStream的基础上,增加的方法:
writeXxx(…):
DataInputStream在InputStream的基础上,增加的方法:
readXxx():
用DataOutputStream写的数据/文件,用DataInputStream读取,并且要求读的顺序与写的顺序一致
@Test
public void test5() throws IOException{
int num=1;
char c='好';
double d=3.4;
String info="哈哈哈";
boolean b=true;
FileOutputStream fos=new FileOutputStream("3.dat");
DataOutputStream dos=new DataOutputStream(fos);
dos.writeInt(num);
dos.writeChar(c);
dos.writeDouble(d);
dos.writeUTF(info);
dos.writeBoolean(b);
dos.close();
fos.close();
}
@Test
public void test6() throws IOException{
FileInputStream fis=new FileInputStream("3.dat");
DataInputStream dis=new DataInputStream(fis);
int num=dis.readInt();
char c=dis.readChar();
double d=dis.readDouble();
String info=dis.readUTF();
boolean b=dis.readBoolean();
System.out.println(num);
System.out.println(c);
System.out.println(d);
System.out.println(info);
System.out.println(b);
dis.close();
fis.close();
}
- 序列化与反序列化
(1)java.io.Serializable接口
ObjectOutputStream:用于输出对象,即把对象转成字节数据输出,对象的输出过程称为序列化;ObjectOutputStream比OutputStream多的方法之一:writeObject(obj)
如果创建对象的类没有实现Serializable接口,在序列化时,会报错NotSerializableException,不能序列化,因此,类必须实现java.io.Serializable接口
(2)ObjectInputStream:用于输入对象,把字节序列转为对象读取,对象的读取过程称为反序列化;ObjectInputStream比InputStream多的方法之一:Object readObject()
当对象已经输出到文件后修改了类,再次读取这个文件时,报错InvalidClassException,报错的原因:流中关于类的serialVersionUID与本地类的serialVersionUID对不上,就会报错InvalidClassException;
如何解决?修改本地的serializableUID为流中的serialVersionUID;或者在实现Serializable接口时固定一个serialVersionUID
(3)序列化一个对象时,要求它的属性是基本数据类型,如果是引用数据类型,那么这个引用数据类型也必须实现Serializable接口
序列化一个数组,要求元素类型实现Serializable接口
@Test
public void test7() throws IOException{
User u=new User("lx","123456");
FileOutputStream fos=new FileOutputStream("3.dat");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(u);
oos.close();
fos.close();
}
@Test
public void test8() throws IOException,ClassNotFoundException{
FileInputStream fis=new FileInputStream("3.dat");
ObjectInputStream ois=new ObjectInputStream(fis);
Object obj=ois.readObject();
System.out.println(obj);
ois.close();
fis.close();
}
//实现Serializable接口
class User implements Serializable{
private static final long serivalVersionUID=1L;
private String name;
private String id;
public User(String name, String id) {
super();
this.name = name;
this.id = id;
}
//实现Externalizable
class User implements Externalizable{
private static final long serivalVersionUID=1L;
private String name;
private String id;
public User(String name, String id) {
super();
this.name = name;
this.id = id;
}
@Override
public void writeExternal(ObjectOutput out) throws TOException{
out.writeUTF(name);
out.writeUTF(id):
}
@Override
public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException{
name = in.readUTF();
id = in.readUTF();
}
}
(4)不序列化的字段:
不是对象的所有属性都需要序列化
如果某个属性不需要序列化,可以在属性的前面加一个关键字:transient
如果某个属性是static,也不会序列化,因为静态变量不属于某个对象,而是整个类,所以不需要随着对象的序列化而序列化
(5)java.io.Externalizable接口
若要完全控制某一个对象的流格式和内容,则它要实现Externalizable接口的writeExternal和readExternal方法,程序员在writeExternal方法中,自己定制哪些属性要序列化及其顺序;在readExternal方法中,自己定制哪些属性要反序列化及其顺序
JDK1.7新增try…catch
try(
需要关闭的资源对象
){
可能发生异常的逻辑代码
}catch(异常对象 e){
异常处理代码
}catch(异常对象 e){
异常处理代码
}
凡是在try()中声明的资源对象,无论是否发生异常都会自动关闭
@Test
public void test2(){
try(
FileInputStream fis=new FileInputStream("1.txt");
InputStreamReader isr=new InputStreamReader(fis,"GBK");
BufferedReader br=new BufferedReader(isr);
FileOutputStream fos=new FileOutputStream("1.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
BufferedWriter bw=new BufferedWriter(osw);
){
String str;
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}