I/O流概述:
i:Input,以内存为基准,表示从硬盘中读取数据到内存中。
o: Outerput,以内存为基准,表示将内存中的数据写到硬盘中。
I/O流体系
原始流
1、原始字节流
-
FileInputStream: (文件字节输入流)
作用:将文件中的字节读取到内存中来。
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件路径
InputStream is = new FileInputStream(f); //以多态形式 创建了一个文件字节输入流管道
int data = is.read(); //读取is管道中的一个字节, 返回结果为ASCII编码的数值形式
System.out.println((char) data); //结果:a
int data2 = is.read(); //继续读取is管道中的第二个字节
System.out.println((char) data2); //结果:b
int data3 = is.read(); //文件读取完毕后将返回-1
System.out.println(data3); //结果:-1
is.close(); //关闭管道
}
}
上述代码简单易懂,但读取效率低下。因为在读取管道字节时是一个字节一个字节读取的,我们可以想法一次多读几个字节,减少读取次数,从而提高读取效率。
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //文件内容:abc123ab
InputStream is = new FileInputStream(f);
byte[] buffer = new byte[3]; //定义一个字节数组,每次在管道中读取3个字节
is.read(buffer); //buffer数组相当于一个水桶,每次在is管道中接3个字节
String data = new String(buffer); //将字节数组解码为字符串。
System.out.println(data); //结果:abc
is.read(buffer);
String data2 = new String(buffer);
System.out.println(data2); //结果:123
is.read(buffer);
String data3 = new String(buffer);
System.out.println(data3); //结果:ab3 //预期结果应该为ab才对呀。原因是最后一桶水没有装满,3是残留的上一桶的
/*
解决方案:
在is.read(buffer)读取管道字节时,会返回读取的字节个数,
可以在解码字节数组时,指定长度(接多少读多少)
int len;
while ((len = is.read(buffer))!= -1) {
String data = new String(buffer, 0, len); //接多少读多少
System.out.println(data);
}
*/
is.close(); //在不用此管道时须关闭管道,否则会影响cpu性能
}
}
-
FileOutputStream:(文件字节输出流)
作用:将内存中的字节写入到硬盘文件中去。
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位要写入到的文件路径,没有则自动创建
OutputStream os = new FileOutputStream(f); //创建文件字节输出流管道,连接内存与磁盘文件
os.write('a'); //将一个字节a 利用os管道写入到文件中 //os.write(97); //效果相同
byte[] data = {'a','b','c'};
os.write(data); //将字节数组写入到文件中
byte[] data2 = "我爱迪迪".getBytes(); //将字符串转换成字节数组
os.write(data2);
//os.flush(); //写数据到文件最后一定要刷新, 因为写的速度比较慢,可能会有数据还在管道中
os.close(); //关闭管道,会自动刷新管道。
}
}
2、原始字符流
-
FileReader:(文件字符输入流)
作用:将文件中的的字符读取到内存中来
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件路径 ab爱
Reader rs = new FileReader(f); //以多态形式,创建一个字符输入流管道
int data = rs.read(); //从字符输入流管道中读取一个字符 以ASCII码数值形式返回
System.out.println((char) data); //a
int data2 = rs.read();
System.out.println((char) data2); //b
int data3 = rs.read();
System.out.println((char) data3); //爱 //用字符输入流读取中文不存在乱码现象
int data4 = rs.read();
System.out.println(data4); //-1 //读取完毕返回-1
}
}
与字节输入流类似。上述代码只能从字符输入流中一次读取一个字符,可以用一个字符数组一次读取多个字符,提高读取效率。
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //ab爱123a
Reader rs = new FileReader(f);
char[] buffer = new char[3]; //定义一个字符数组,相当于一个水桶每次在字符输入流中提取3个字符
rs.read(buffer); //拿着buffer去读取字符,每次读取3个字符
System.out.println(buffer); //ab爱
rs.read(buffer);
System.out.println(buffer); //123
rs.read(buffer);
System.out.println(buffer); //a23 //预期应为a,原因是因为残留的上一次的
/*
解决方案:
int len;
while ((len = rs.read(buffer)) != -1) {
String data = new String(buffer, 0, len); //接多少读取多少
System.out.println(data);
}
*/
}
}
-
FileWrite:(文件字符输出流)
作用:将文件中的字符写入到文件中去。
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件
Writer wr = new FileWriter(f); //定义一个文件字符输出流文件
wr.write(97); //写字符a到文件
wr.write('a'); //写字符a到文件
wr.write("我爱迪迪"); //也可直接写字符串到文件
//wr.flush(); //刷新管道, 写数据到文件一定要刷新。
wr.close(); //关闭管道 会默认刷新管道
}
}
高级流
一、缓冲流
概述:缓冲流自带缓冲区可以提高原始流的读写效率。cpu处理磁盘文件比较慢,而利用缓冲区就不需要直接对磁盘进行操作,仅对缓冲区进行操作,从而提高读写效率。
1.字节缓冲流
- BufferedInputStream: (缓冲字节输入流)
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件
InputStream is = new FileInputStream(f); //创建普通文件字节输入流
InputStream bis = new BufferedInputStream(is); //将文件字节输入流包装成 缓冲字节输入流. 此时可以像操作低级流一样操作bis.
byte[] buffer = new byte[3];
int len;
while ((len = bis.read(buffer)) != -1) {
System.out.print(new String(buffer,0, len)); //每桶接多少读多少
}
}
}
- BufferedOutputStream: (缓冲字节输出流)
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件
OutputStream os = new FileOutputStream(f); //创建普通字节输出流
OutputStream bos = new BufferedOutputStream(os); //将普通字节输出流 包装成 缓冲字节输出流,此时可以像操作普通字节输出流一样操作bos
bos.write(97); //写一个字节a到文件
bos.write('a'); //写一个字节a到文件
byte[] data = {'a','b','c'}; //写一个字节数组到文件
bos.write(data);
byte[] data2 = "我爱你".getBytes(); // getBytes(): 将字符串转换成字节数组
bos.write(data2); //写一个字节数组到文件
bos.close();
}
}
2、字符缓冲流
- BufferedReader: (缓冲字符输入流)
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件
Reader rs = new FileReader(f); //普通文件字符输入流
BufferedReader brs = new BufferedReader(rs); //将普通文件字符输入流 包装成 缓冲字符输入流。 此时缓冲流brs可以像普通字符输入流一样操作
String info;
while ((info = brs.readLine()) != null) { //字符缓冲输入流新增功能 readLine():读取一行
System.out.println(info);
}
}
}
- BufferedWriter: (缓冲字符输出流)
public class Demo {
public static void main(String[] args) throws Exception {
File f = new File("javase/src/code/word.txt"); //定位文件
Writer w = new FileWriter(f,true); //定义普通文件字符输出流 //在低级文件输出流中加true可追加文件
Writer bw = new BufferedWriter(w); //将文件字符输出流 包装成 缓冲字符输出流,
bw.write('a');
bw.write("我爱你");
bw.close();
}
}
缓冲流总结:缓冲流并不复杂,仅仅是在普通文件流的基础上加了一层包装,用于提高文件读写的效率。
二、打印流
作用:可以方便、高效的将内存中的数据打印到文件中去。打印什么就是什么,例如将97打印到文件中就是97,而不是a。
1、PrintStream
public class Demo {
public static void main(String[] args) throws Exception {
/*
创建打印流对象:
方式一: new PrintStream(文件对象)
方式二: new PrintStream("文件路径")
方式三: new PrintStream(字节输出流对象)
*/
//方式一
File f = new File("javase/src/code/word.txt");
PrintStream ps = new PrintStream(f);
ps.println(97); //97
ps.println('a'); //a
ps.println("我爱迪迪"); //我爱迪迪
//方式二
PrintStream ps2 = new PrintStream("javase/src/code/word.txt");
ps2.println(97); //97
ps2.println('a'); //a
ps2.println("我爱迪迪"); //我爱迪迪
//方式三
OutputStream os = new FileOutputStream("javase/src/code/word.txt",true); //添加true参数可以追加文件数据,而非覆盖
PrintStream ps3 = new PrintStream(os);
ps3.println(97); //97
ps3.println('a'); //a
ps3.println("我爱迪迪"); //我爱迪迪
}
}
2、PrintWriter
public class Demo {
public static void main(String[] args) throws Exception {
/*
创建打印流对象:
方式一: new PrintWriter(文件对象)
方式二: new PrintWriter("文件路径")
方式三: new PrintWriter(字节输出流对象)
方式四: new PrintWriter(字符输出流对象)
*/
//方式一:
File f = new File("javase/src/code/word.txt");
PrintWriter pw = new PrintWriter(f);
pw.println(97); //97 //pw.write(97);
pw.println('a'); //a //pw.write('a');
pw.println("我爱迪迪"); //我爱迪迪 //pw.write("我爱迪迪");
pw.close(); //关闭打印流
//方式二:
PrintWriter pw2 = new PrintWriter("javase/src/code/word.txt");
pw2.println(97); //97 //pw2.write(97);
pw2.println('a'); //a //pw2.write('a');
pw2.println("我爱迪迪2"); //我爱迪迪 //pw2.write("我爱迪迪2");
pw2.close(); //关闭打印流
//方式三:
PrintWriter pw3 = new PrintWriter(new FileOutputStream("javase/src/code/word.txt",true));
pw3.println(97); //97 //pw3.write(97);
pw3.println('a'); //a //pw3.write('a');
pw3.println("我爱迪迪3"); //我爱迪迪 //pw3.write("我爱迪迪3");
pw3.close(); //关闭打印流
//方式四
PrintWriter pw4 = new PrintWriter(new FileWriter("javase/src/code/word.txt",true));
pw4.println(97); //97 //pw4.write(97);
pw4.println('a'); //a //pw4.write('a');
pw4.println("我爱迪迪4"); //我爱迪迪 //pw4.write("我爱迪迪4");
pw4.close(); //关闭打印流
}
}
总结:PrintStream与PrintWriter差比很小,几乎可以混用,一般使用PrintStream就可以。
三、转换流
-
InputStreamReader:(字符转换输入流)
作用:将文件以某种指定的字符格式读取。
public class Demo {
public static void main(String[] args) throws Exception {
/*
转换步骤:
1.获取数据的文件字节输入流
2.将得到的文件字节输入流转换为指定格式的字符流
*/
InputStream is = new FileInputStream("D:/桌面/word2.txt"); //原始字节输入流 word2.txt为GBK形式
Reader isr = new InputStreamReader(is, "GBK"); //将原始字节输入流,以指定的GBK编码形式转换成字符输入流。
BufferedReader br = new BufferedReader(isr);
String info;
while ((info = br.readLine()) != null) {
System.out.println(info);
}
}
}
-
OutputStreamReader:(字符转换输出流)
作用:将内存中的数据以指定格式写入磁盘文件。
public class Demo {
public static void main(String[] args) throws Exception {
/*
转换步骤:
1.获取原始字节输出流
2.将得到的原始字节输出流转换成指定格式的字符输出流
*/
OutputStream os = new FileOutputStream("D:/桌面/word2.txt");
Writer w = new OutputStreamWriter(os, "GBK"); //创建以GBK格式的输出管道
w.write("我爱你");
w.close();
}
}
四、对象序列化
对象字节输出流:ObjectOutputStream
概念:将内存中的对象储存到磁盘文件中去。
public class Demo {
public static void main(String[] args) throws Exception {
OutputStream os = new FileOutputStream("javase/src/code/word.txt"); //原始文件字节输出流
ObjectOutputStream oos = new ObjectOutputStream(os); //将原始文件字节输出流包装成对象输出流
Student s1 = new Student("王小二", 21); //注意:student此类必须实现Serializable接口
oos.writeObject(s1); //将对象储存到文件中
oos.close();
}
}
五、对象反序列化
对象字节输入流:ObjectInputStream
概念:将磁盘文件中的对象恢复到内存中来。
public class Demo {
public static void main(String[] args) throws Exception {
InputStream os = new FileInputStream("javase/src/code/word.txt"); //创建原始字节输入流
ObjectInputStream ois = new ObjectInputStream(os); //将原始字节输入流包装成 对象输入流
Student s = (Student) ois.readObject(); //对象反序列化
System.out.println(s);
}
}