简单来讲:
你编写了一个java程序,
你用这个java程序从你的电脑上读取文件,就是输入流;
你把你所写的java程序的数据传递给某个文件,就是输出流;
一、四大家族的首领:
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流
四大家族的首领都是抽象类。(abstract class)
java.io包下需要掌握的流有16个:
文件专属:
java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter
转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter
缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
数据流专属:
java.io.DataInputStream
java.io.DataOutputStream
标准输出流:
java.io.PrintWriter
java.io.PrintStream(掌握)
对象专属流:
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream(掌握)
二、举例
1.FileInputStream
| 方法摘要 | 方法 | 作用 |
|---|---|---|
| abstract int | read() | 从输入流中读取数据的下一个字节 |
| int | read(byte[] b) | 将输入流中读取一定数量 并将其存储在缓冲区数组 b 中。 |
| int | read(byte[] b, int off, int len) | 将输入流中最多 len 个数据字节读入 byte 数组。返回总字节数. |
演示read[byte[] b]:
下面while()的初始版
fis=new FileInputStream("E:\\IO\\ceshi\\finally.text");byte[] bytes=new byte[4];/* while(true){int readcount=fis.read(bytes);if(readcount=-1){break;}//把byte数组转化为字符串,读到几个转换几个System.out.print(new String(bytes,0,readCount));}*/
最终版:
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class Finally {public static void main(String[] args) {FileInputStream fis =null;try {fis=new FileInputStream("E:\\IO\\ceshi\\finally.text");//准备一个byte数组byte[] bytes=new byte[4];int readCount=0;//read(bytes)方法是读到的字节个数为几个,当读到没有时返回-1while ((readCount=fis.read(bytes))!=-1){//把byte数组转化为字符串,读到几个转换几个System.out.print(new String(bytes,0,readCount));}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(fis!=null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}}
abcdef
2.FileOutputStream
import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class OutTest {public static void main(String[] args) {FileOutputStream fos=null;try {//这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入// fos=new FileOutputStream("E:\\IO\\ceshi\\finally.text");//以追加的方式在文件末尾写入。不会清除原文件内容。fos=new FileOutputStream("E:\\IO\\ceshi\\finally.text",true);byte[] bytes ={97,98,99,100};//将byte数组全部写出!fos.write(bytes);//abcd//将byte数组一部分写出!fos.write(bytes,0,2);//再写出ab//写完之后一定要刷新fos.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(fos!=null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}}
3.所有文件的复制
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;public class OutTest {public static void main(String[] args) {FileInputStream fis=null;FileOutputStream fos=null;try {fis=new FileInputStream("E:\\IO\\ceshi\\resource.txt");fos=new FileOutputStream("E:\\IO\\ceshi2\\position.txt");//最核心的:一边读,一边写byte [] bytes = new byte[1024*1024];//1MB(最多可拷贝1MB)int readCount=0;while ((readCount=fis.read(bytes))!=-1){fos.write(bytes,0,readCount);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//分开try,不要一起tryif(fis!=null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}if(fos!=null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}}
4.java.io.BufferedReader和转换流
import java.io.*;/*带有缓冲区的字符输入流使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲。*/public class BufferedReaderTest {public static void main(String[] args) throws IOException {/*这个构造方法只能传一个字符流。不能传字节流//通过转换流转换(InputStreamReader将字节流转换为字符流)FileInputStream是节点流,BufferedReader是包装流。*/BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\IO\\ceshi\\finally.text")));//br.readLine读一行String Line = null;while ((Line = br.readLine()) != null) {System.out.println(Line);}//关闭流//对于包装流来说,只需要关闭最外层流就行,里面的节点流自动关闭(可以看源码)br.close();}}
5.DataOutputStream和DataInputStream
/*java.io.DataOutputStream:数据专属的流。这个流可以将数据连同数据的类型一并写入文件。注意:这个文件不是普通文本文档。(这个文件使用记事本打不开。)*//*DataInputStream:数据字节输入流。DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。读的顺序需要和写的顺序一致。才可以正常取出数据。*/import java.io.DataOutputStream;import java.io.FileOutputStream;import java.io.IOException;public class Data {public static void main(String[] args) throws IOException {//创建数据专属的字节输出流//Dataoutputstream(Outputstream) Outputstream是抽象类无法实例化,我们可以new 他的子类DataOutputStream dos=new DataOutputStream(new FileOutputStream("E:\\IO\\ceshi\\finally.text"));//写数据int i=300;boolean sex=false;char c='a';//写dos.writeInt(i);dos.writeBoolean(sex);dos.writeChar(c);//刷新dos.flush();//关闭最外层dos.close();}}
6.标准输出流
标准输出流是不需要关闭流的
import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.PrintStream;import java.text.SimpleDateFormat;import java.util.Date;public class Logger {public static void log(String msg){try {//指向一个日志文件PrintStream out=new PrintStream(new FileOutputStream("log.txt",true));//改变输出方向System.setOut(out);//日期当前时间Date nowTime = new Date();SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss: SSS");String strTime =sdf.format(nowTime);System.out.println(strTime+":"+msg);} catch (FileNotFoundException e) {e.printStackTrace();}}}
public class LogTest {public static void main(String[] args) {//测试工具类Logger.log("调用了System类的gc方法,建议启动垃圾回收");Logger.log("调用了UserService的doSome()方法");Logger.log("用户尝试登陆,验证失败");Logger.log("我非常喜欢这个记录工具哦");}}
2021-11-10 17:12:04: 764:调用了System类的gc方法,建议启动垃圾回收2021-11-10 17:12:04: 797:调用了UserService的doSome()方法2021-11-10 17:12:04: 801:用户尝试登陆,验证失败2021-11-10 17:12:04: 801:我非常喜欢这个记录工具哦
7.序列化和反序列化

1:参与序列化和反序列化的对象,必须实现Serializable接口。
注意:通过源代码发现,Serializable接口只是一个标志接口:
public interface Serializable {
}
2
凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。
这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类。
3:
transient关键字表示游离的,不参与序列化。
private transient String name; // name不参与序列化操作
package com.bjpowernode.java.io;import java.io.Serializable;public class Student implements Serializable {private static final long serialVersionUID = 1L;// java虚拟机识别一个类的时候先通过类名,如果类名一致,再通过序列化版本号。private int no;private String name;public Student() {}public Student(int no, String name) {this.no = no;this.name = name;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student{" +"no=" + no +", name='" + name + '\'' +'}';}}
package com.bjpowernode.java.io;import java.io.FileOutputStream;import java.io.ObjectOutputStream;public class ObjectOutputStreamTest01 {public static void main(String[] args)throws Exception {//创建java对象Student s =new Student(111,"zhangsan");//序列化ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("students"));//序列化对象oos.writeObject(s);//刷新oos.flush();//关闭oos.close();}}
一次性序列多个对象(参考)
/*一次序列化多个对象呢?可以,可以将对象放到集合当中,序列化集合。提示:参与序列化的ArrayList集合以及集合中的元素User都需要实现 java.io.Serializable接口。*/public class ObjectOutputStreamTest02 {public static void main(String[] args) throws Exception{List<User> userList = new ArrayList<>();userList.add(new User(1,"zhangsan"));userList.add(new User(2, "lisi"));userList.add(new User(3, "wangwu"));ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));// 序列化一个集合,这个集合对象中放了很多其他对象。oos.writeObject(userList);oos.flush();oos.close();}}
8.IO流和Properties的使用
userinfo.properties
username=adminpassword=123
import java.io.FileReader;import java.util.Properties;public class IoPropertiesTest01 {public static void main(String[] args) throws Exception {//新建一个输入流对象FileReader reader =new FileReader("src/userinfo.properties");//新建一个Map集合Properties pro=new Properties();//调用properties对象的load方法将文件中的数据加载到Map集合中pro.load(reader);//通过key来获取valueString username=pro.getProperty("username");System.out.println(username);String password=pro.getProperty("password");System.out.println(password);}}
9.File类常用方法
Files.exists():检测⽂件路径是否存在。
Files.createFile():创建⽂件。
Files.createDirectory():创建⽂件夹。
Files.delete():删除⼀个⽂件或⽬录。
Files.copy():复制⽂件。
Files.move():移动⽂件。
Files.size():查看⽂件个数。
Files.read():读取⽂件。
Files.write():写⼊⽂件。
三、面试题
1.序列化和反序列化
- 序列化: 将对象转换成二进制字节流的过程
- 反序列化:将在序列化过程中所生成的二进制字节流转换成对象的过程
序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要的时候把该流读取出来重新构造成一个相同的对象。

