1.IO->Input Output
2.按照流的读写方式:字节流和字符流
3.按照流的方向:输入流和输出流
InputStream abstract修饰
Reader abstract
OutputStream abstract
Writer abstract
4.输入流的核心方法:read()
输出流的核心方法:write()
5.操作的数组类型:
字节流:byte类型
InputStream:
int read(byte[] b):
OutputStream:
void write(byte[] b)
字符流:char类型
Reader:
int read( char[] cbuf)
Writer:
void write(char[] cbuf)
6.FileInputStream和FileOutputStream
使用步骤:
-
选择流类(输入还是输出)
-
确定方法(read还是write)
-
关闭流 close:
由源码可以发现,FileOutputStream是一个普通类,可以创建实例
构造方法可以抛异常
/**
* 1.选择一个流
* 2.选择方法读写
* 3.关闭流
*
*/
public class Demo {
//文件的写操作a.txt 字符
//运行结果:a.txt中有"hello"
public static void test1() throws IOException {
//输出流,如果数据文件存在,那么使用此数据文件
// 如果数据文件不存在,自动创建一个文件,在当前工程文件夹下
FileOutputStream out=new FileOutputStream("a.txt");
//读写方法和close方法都有异常
//out.write("hello".getBytes());// String into a sequence of bytes
out.write("学习".getBytes()); //原本a.txt中是hello,会直接覆盖,变为 学习
out.close();
}
//运行结果:控制台输出hello
//文件的读操作 从a.txt文件中读取数据
public static void test2() throws IOException {
File file=new File("a.txt");
//判断文件是否存在
if(!file.exists()) {//不存在
file.createNewFile();//创建文件
}
//创建文件输入流对象
FileInputStream in=new FileInputStream(file);
byte[] buf=new byte[(int)file.length()];//定义数组
in.read(buf);//把数据读到数组中
System.out.println(new String(buf));//把数组转换成字符串
in.close();
}
public static void test3() throws IOException {
File file=new File("a.txt");
//判断文件是否存在
if(!file.exists()) {//不存在
file.createNewFile();//创建文件
}
//创建文件输入流对象
FileInputStream in=new FileInputStream(file);
int n=0;
//返回的是int,打印的是Ascll码值,要输出字符需要强制转换成char
//test1()中 out.write("hello".getBytes()); 此时写这个不会乱码
//控制台输出 hello
/*while((n=in.read())!=-1) {
System.out.print((char)n);
}*/
//GBK 2个字节
//test1()中 out.write("学习".getBytes()); 控制台输出 学习
byte[] b=new byte[2];
while((n=in.read(b))!=-1) {
System.out.print(new String(b)); //转为字符串
}
}
public static void main(String[] args) throws IOException {
test1();
test2();
}
}
关于test3()中为啥判断等于-1,看下面源码:
含两个参数的文本输出流:
//含两个参数的文本输出流
public static void test4() throws IOException {
FileOutputStream out=new FileOutputStream("a.txt",true);//如果为true,追加文本到末尾
//换行
out.write("hello\n".getBytes());
out.close();
}
结果为:a.txt中内容
学习hello
hello
含两个参数的文本输出流源码如下:
7.对象的输入流和输出流
对象的序列化:把对象转换成二进制的流,写到数据文件
对象的反序列化:把数据文件中二进制的流代表的数据,恢复为对象
8.按照是否能直接操作数据文件:
节点流:直接在构造方法中传入要读写的文件对象或文件名
处理流:不能直接在构造方法中传入要读写的文件对象或文件名
//写对象到数据文件oos.txt
public static void test1() throws FileNotFoundException, IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("oos.txt"));
Student stu1=new Student("admin",18);
Student stu2=new Student("张三",18);
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.close();
}
//读取对象
public static void test2() throws FileNotFoundException, IOException, ClassNotFoundException {
File file=new File("oos.txt");
if(!file.exists()) {
file.createNewFile();
}
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
Student stu1=(Student)ois.readObject();
Student stu2=(Student)ois.readObject();
System.out.println(stu1);
System.out.println(stu2);
ois.close();
}
//结果为:
//Student [name=admin, age=18]
//Student [name=张三, age=18]
序列化版本号的用处:
在序列化存储/反序列化读取或者是序列化传输/反序列化接收时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
1.不修改属性,只改版本号,则异常:
//版本号:
private static final long serialVersionUID = 4236678034618399185L;
//写对象到数据文件oos.txt
public static void test1() throws FileNotFoundException, IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("oos.txt",true));
Student stu1=new Student("admin",18);
Student stu2=new Student("张三",18);
oos.writeObject(stu1);
oos.writeObject(stu2);
oos.close();
}
运行结果正常;
//修改版本号:
private static final long serialVersionUID = 3236678034618399185L;
运行test1(),发现oos.txt多了内容。
运行test2()结果:
2.只要同一个版本号,修改属性,也能反序列化
当你序列化了一个类实例后,希望更改一个字段或添加一个字段,不设置serialVersionUID,所做的任何更改都将导致无法反序化旧有实例,并在反序列化时抛出一个异常。如果你添加了serialVersionUID,在反序列旧有实例时,新添加或更改的字段值将设为初始化值(对象为null,基本类型为相应的初始默认值),字段被删除将不设置
证明1.不设置版本号,并增加字段
//private static final long serialVersionUID = 4236678034618399185L;
String sex;
证明2.有版本号,重写toString()
private static final long serialVersionUID = 4236678034618399185L;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
结果为:
Student [name=admin, age=18, sex=null]
Student [name=张三, age=18, sex=null]
9.FileReader和FileWriter
public static void test1() throws IOException {
FileWriter fw=new FileWriter("fw.txt");
fw.write("hello学习");
fw.close();
}
public static void test2() throws IOException {
File file=new File("fw.txt");
if(!file.exists()) {
file.createNewFile();
}
FileReader fr=new FileReader(file);
char[] buf=new char[(int) file.length()];
fr.read(buf);
System.out.println(new String(buf));
}
结果:
hello学习
练习:
//练习:复制fw.txt内容到fw1.txt文件中
public static void test3() throws IOException {
File file=new File("fw.txt");
if(!file.exists()) {
file.createNewFile();
}
FileReader fr=new FileReader(file);
char[] buf=new char[(int) file.length()];
fr.read(buf);
FileWriter fw1=new FileWriter("fw1.txt");
fw1.write(buf);
fw1.close();
fr.close();
}
10.缓冲流 :BufferdReader 和 BufferdWriter 读写效率最高
readLine()
打印流 :PrintWriter();
println();
public static void test1() throws FileNotFoundException {
//创建一个缓存的输入流的对象
PrintWriter pw=new PrintWriter("pw.txt");
//自动换行
pw.println("张三 13223543217 zhangsan@tedu.cn");
pw.println("李四 13223543217 lisi@tedu.cn");
pw.close();
}
public static void test2() throws IOException {
BufferedReader br=new BufferedReader(new FileReader("pw.txt"));
String str="";
//readLine方法,返回一行,如果返回值为null,说明文件内容读取完毕
while((str=br.readLine())!=null) {
String[] value=str.split("\\s"); // \\s表示一个空格
String name=value[0];
String phone=value[1];
String email=value[2];
System.out.println("姓名:"+name+",电话:"+phone+",邮箱:"+email);
}
br.close();
}
运行结果:
姓名:张三,电话:13223543217,邮箱:zhangsan@tedu.cn
姓名:李四,电话:13223543217,邮箱:lisi@tedu.cn
11.转换流:InputStreamReader OutputStreamWriter
InputStream ins=new FileInputStream("ins.txt");
BufferedReader br=new BufferedReader(new InputStreamReader(ins));
12.输入流和输出流是一个流对象,RandomAccessFile类
r-----输入流
rw-----输出流
小结:
File
FileInputStream FileOutputStream
ObjectInputStream ObjectOutputStream
FileReader FileWriter
BufferedReader PrintWriter
InputStreamReader OutputStreamWriter