IO流
以流的方向:
- 输入流(input、read读)
- 输出流(output、write写)
以读取数据类型:
- 字节流
- 字符流
字节流
以Stream结尾的都是字节流。
以字节为单位,一次读取一个字节,可以读图片、文档、视频、音频等。
字符流
以Writer或Reader结尾的都是字符流。
以字符为单位,一次读一个字符,只能读取纯文本文件。
文件专属流
FileInputStream
- read()(获取当前读到字节)
- read(byte)(把读到的字节放到数组中,一次放byte.length)
- skip(x)(跳过x个字节读)
- available()(获取还未读的字节个数)
FileInputStream fis = null;
try {
fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\小结.txt");
byte[] bytes = new byte[10];
//记录读取的一次读取信息到的个数
int count=0;
//文件读取一次读10个,并把数据放入bytes数组中,如果没有读到信息就返回-1
while((count=fis.read(bytes))!=-1){
//将bytes数组转换成字符串,从下标bytrs[0]开始,一次转换count个
System.out.print(new String(bytes,0,count));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {//如果流不是空,就关闭流
try {
fis.close();//及时关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream
- write()(写入数据)
- flush()(刷新流通道)
FileOutputStream fos=null;
try {
//指定文件位置,true代表可以继续写入,而不是覆盖原文件的内容
fos=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\qq.txt",true);
String str="ajbdfuyshyfyrdkjgh可hi应嘎是gd";
//将String转换成byte数组
byte[] bytes = str.getBytes();
//将数组写入文件
fos.write(bytes);
fos.flush();//刷新
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader
以字符的形式读。
FileWriter
以字符的形式写。
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader("qq.txt");
fw=new FileWriter("qq.txt",true);//续写到文件中
char[] chars=new char[10];//一次读10个字符
int count=0;
//一边读,一边写。可以实现拷贝文件。
while((count=fr.read(chars))!=-1){
fw.write(chars,0,count);//写入
}
fw.flush();//刷新
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
if (fw != null) {
try {
fw.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流
BufferedReader
- readLine()(读一行)
缓冲流可以一次读一行,就不需要再指定数组了。
BufferedWriter
BufferedInputStream
BufferedOutputStream
BufferedReader br = null;
BufferedWriter bw=null;
FileOutputStream fw=null;
try {
FileReader fr = new FileReader("Hello/src/base/IO流/CopyDemo1.java");
br = new BufferedReader(fr);//放的是字符流
fw= new FileOutputStream("qq");//以字节流的形式xier
String data=null;
while((data=br.readLine())!=null){
fw.write(data.getBytes());//读和写不需要一样,用字符流读的文件,也可以用字节流写。
}
fw.flush();//刷新
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();//关闭流只需要关闭最外边的。
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流
InputStreamReader
可以将字节输入流转换为字符输入流
FileInputStream fis=new FileInputStream("qq.txt");
InputStreamReader ir=new InputStreamReader(fis);//将字节流转换成字符流
OutputStreamWriter
可以将字节输出流转换为字符输出流
new OutputStreamWriter(new FileOutputStream("qq")
数据专属流
DataInputStream
可以读取数据的类型和值。
DataInputStream dis=null;
try {
dis=new DataInputStream(new FileInputStream("qq"));
byte b = dis.readByte();//可以读到数据的类型。
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
boolean flag = dis.readBoolean();
char c = dis.readChar();
System.out.println(b);//100
System.out.println(s);//200
System.out.println(i);//300
System.out.println(l);//400
System.out.println(f);//500.0
System.out.println(d);//600.0
System.out.println(flag);//false
System.out.println(c);//c
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
DataOutputStream
可以写入数据的类型。
DataOutputStream dos=null;
try {
dos=new DataOutputStream(new FileOutputStream("qq"));
byte b=100;
short s=200;
int i=300;
long l=400;
float f=500.0f;
double d=600.0;
boolean flag=false;
char c='c';
dos.writeByte(b);//根据数据类型调用不同方法保存数据。
dos.writeShort(s);
dos.writeInt(i);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeBoolean(flag);
dos.writeChar(c);
dos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
标准输出流
PrintWriter
PrintStream
//标准输出流不需要手动关闭
PrintStream ps=null;
System.out.println("张飞");//现在是输出到控制台中
try {
ps=new PrintStream("log");
System.setOut(ps);//改变输出方向
Date date=new Date();//获取当前时间。
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");//设置时间格式
String time = simpleDateFormat.format(date);
System.out.println(time+"用户登录失败");
System.out.println(time+"用户重新登录");
System.out.println(time+"用户登录还是失败");
System.out.println(time+"用户走了");
//以上信息不会显示到控制台中,而是会输入到log文件中。
} catch (FileNotFoundException e) {
e.printStackTrace();
}
对象专属流
ObjectOutputStream
将对象写入硬盘中。这个过程也叫序列化。
User user1=new User(111,"张飞");
ObjectOutputStream oos=null;
try {
oos=new ObjectOutputStream(new FileOutputStream("Three Country"));
//序列化
oos.writeObject(user1);//将对象写入Three Country文件中
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (oos != null) {
try {
oos.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectInputStream
将对象从硬盘中读出来。这个过程也叫反序列化。
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(new FileInputStream("Three Country"));
System.out.println(ois.readObject());//读User类型
//User{id=0, name='张飞', gender=null}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
也可以存多个对象,以List的形式。
//创建User对象
User user1=new User(111,"张飞");
User user2=new User(222,"关羽");
User user3=new User(111,"赵云");
ObjectOutputStream oos2=null;
try {
oos2=new ObjectOutputStream(new FileOutputStream("Three Country2"));
//序列化
List<User> list=new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user3);
oos2.writeObject(list);
oos2.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (oos2 != null) {
try {
oos2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ObjectInputStream ois2=null;
try {
ois2=new ObjectInputStream(new FileInputStream("Three Country2"));
//反序列化
System.out.println(ois2.readObject());//读List类型
//[User{id=0, name='张飞', gender=null}, User{id=0, name='关羽', gender=null}, User{id=0, name='赵云', gender=null}, User{id=0, name='赵云', gender=null}]
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois2 != null) {
try {
ois2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意
-
序列化的对象类需要实现Serializable接口
-
当序列化一个对象类后,JVM会默认生成一个序列化版本号。JVM识别一个类先看类名,类名一致再看序列化版本号。此时如果修改对象类的内容,JVM会重写分配一个序列化版本号。当两个序列化版本号不一致时,就会报错。
-
对象类序列化后不能修改,如果修改再执行反序列化会报错。会出现问题。
//InvalidClassException: base.bean.User; // local class incompatible: // stream classdesc serialVersionUID = -2261533198529479100, // local class serialVersionUID = 4860489787298953017
解决方案:
//在对象类中手动增加一个序列化版本号 private static final long serialVersionUID = 1557683056911141067L;
-
private transient int id;//transient游离的,不参加序列化,反序列化时会输出默认值。