流的概念
- 概念:内存与存储设备之间传输数据的通道。
流的分类
-
按方向【重点】
- 输入流:将<存储设备>中的内容读入到<内存>中。
- 输出流:将<内存>中的内容写入到<存储设备>中。
-
按单位
- 字节流:以字节为单位,可以读写所有数据
- 字符流:以字符为单位,只能读写文本数据
-
按功能
- 节点流:具有实际传输数据的读写功能。
- 过滤流:在节点流的基础之上增强功能。
字节流
字节流的父类(抽象类)
InputStream
OutPutStream
FilelnputStream的使用
- public int read(byte[] b) //从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1。
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.String;public class Demo06 {public static void main(String[] args) throws IOException {//1.创建FileInputStream,并指定文件路径FileInputStream fis = new FileInputStream("D:\\aaa.txt");//2.读取文件//2.1单个字节读取
// int data = 0;
// //读完返回-1
// while ((data = fis.read()) != -1) {
// System.out.print((char) data);
// }//2.2一次读取多个字节byte[] buf = new byte[1024];//count返回读取的长度int count = fis.read(buf);System.out.println(new String(buf, 0, count));System.out.println(count);//3.关闭fis.close();System.out.println("执行完毕");}
}
/*
abcdefg
7
执行完毕*/
File0utputStream的使用
- public void write(byte[] b) //一次写多个字节,将b数组中所有字节,写入输出流。
public class Demo07 {public static void main(String[] args) throws IOException {//1.创建文件字节输出流对象,ture的作用是如果已有内容,则追加,如果参数列表只有文件名,这会覆盖,而不是追加FileOutputStream fos = new FileOutputStream("D:\\bbb.txt", true);//2.写文件fos.write(97);fos.write(97);fos.write('c');String string = "helloworld";fos.write(string.getBytes());//3.关闭fos.close();System.out.println("执行完毕");}
}
案例:文件复制
public class Demo08 {public static void main(String[] args) throws IOException {//1.创建流//1.1 文件字节输入流FileInputStream fis = new FileInputStream("D:\\001.jpg");//1.2 文件字节输出流FileOutputStream fos = new FileOutputStream("D:\\002.jpg");//2.一边读,一边写byte[] buf = new byte[1024];int count = 0;while ((count = fis.read(buf)) != -1) {fos.write(buf, 0, count);}//3.关闭fis.close();fos.close();System.out.println("复制完毕");}
}
字节缓冲流
-
缓冲流:BufferedInputStream/BufferedOutputStream
- 提高I0效率,减少访问磁盘的次数;
- 数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close(其中调用了flush)
-
BufferedInputStream
public class Demo09 {public static void main(String[] args) throws IOException {//1.创建BufferedInputStreamFileInputStream fis = new FileInputStream("D:\\aaa.txt");//相当于过滤流,增强节点流fisBufferedInputStream bis = new BufferedInputStream(fis);//2.读取 // int data = 0; // //bis里面其实已经有个缓冲区了,是先把一部分数据(8192byte)读入缓冲区,在一个字节一个字节的给data // while ((data = bis.read()) != -1) { // System.out.print((char) data); // }//也可以指定缓冲区byte[] buf = new byte[1024];int count = 0;while ((count = bis.read(buf)) != -1) {System.out.println(new String(buf, 0, count));}//3.关闭,只关闭bis就行,带就把fis关了bis.close();System.out.println();System.out.println("执行完毕");} } /* abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg执行完毕*/
-
BufferedOutputStream
public class Demo10 {public static void main(String[] args) throws IOException {//1.创建字节输出缓冲流FileOutputStream fos = new FileOutputStream("D:\\buffer.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);//2.写入文件for (int i = 0; i < 10; i++) {bos.write("helloworld\n".getBytes());//写入8k缓冲区bos.flush();//及时刷新到硬盘,避免数据丢失}//3.关闭bos.close();System.out.println("输出完毕");} }
对象流
-
对象流:0bjectOutputStream/0bjectInputStream
-
增强了缓冲区功能
-
增强了读写8种基本数据类型和字符串功能
-
增强了读写对象的功:
-
read0bject()从流中读取一个对象
-
write0bject(0bject obj)向流中写入一个对象编码方式
-
-
使用流传输对象的过程称为序列化(写文件)、反序列化(读取文件)
public class Test {public static void main(String[] args) throws Throwable {//1.创建对象流FileOutputStream fos = new FileOutputStream("D:\\stu.bin");ObjectOutputStream oos = new ObjectOutputStream(fos);//2.序列化(写入操作)//注意,这里Student类要实现Serializable接口,用来标志该类可以序列号,否则报错Student zhangsan = new Student("张三", 18);oos.writeObject(zhangsan);//3.关闭oos.close();System.out.println("序列化完毕");//1.创建对象流FileInputStream fis = new FileInputStream("D:\\stu.bin");ObjectInputStream ois = new ObjectInputStream(fis);//反序列化(读取操作)不能读多个Student s = (Student) ois.readObject();//3.关闭ois.close();System.out.println("反序列化完毕");System.out.println(s);}
}
/*
序列化完毕
反序列化完毕
Student{name='张三', age=18}*/
序列化和反序列化注意事项
- 序列化类必须要实现Serializable接口
- 序列化类中对象属性(即对象的成员变量),这个类也要求实现Serializable接口
- 序列化版本号ID serialVersionUID,保证序列化的类和反序列化的类是同一个类,否则程序不认为是同一个类,会报错
- 使用transient(瞬间的,相对而言,序列化是持久的)修饰属性,这个属性不能序列化
- 静态属性不能被序列化
- 序列化多个对象,可以借助集合实现,也可以一个一个读,一个一个写,就是麻烦点
字符编码
- IS0-8859-1收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。
- UTF-8 针对Unicode码表的可变长度字符编码
- GB2312 简体中文
- GBK 简体中文、扩充
- BIG5 台湾,繁体中文
注意:当编码方式和解码方式不一致时,会出现乱码。
字符流
字符流的抽象类
案例
public class Demo16 {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("D:\\hello.txt");int data = 0;//文件中为“你好世界”,12个字节4个汉字,而用字节流每个字节单独看,会产生乱码,这是要用到字符流while ((data = fis.read()) != -1) {System.out.print((char) data);}fis.close();}
}
/*
ä½ å¥½ä¸ç*/
- 字符流的父类(抽象类,即用子类实现功能)
- Reader;字符输入流
- public int read () {}
- public int read(char[] c){}
- public int read(char[] b,int off,int len){}
- Writer:字符输出流
- public void write(int n) {}
- public void write(String str){}
- public void write(char[] c) {}
- Reader;字符输入流
文件字符流
- FileReader:
- publicint read(char[] c) //从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回-1。
- FileWriter:
- public void write(String str) //一次写多个字符,将b数组中所有字符,写入输出流。
注意:使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件,因为图片是没有编码的,使用字符流读取写入会转码,会产生乱码,导致写入数据不一致。但使用字节流复制任意文件。
public class Demo17 {public static void main(String[] args) throws IOException {//1.创建FileReader 文件字符输入流FileReader fr = new FileReader("D:\\searchwork\\study\\JavaSE\\hello.txt");//2.读取//2.1单个字符读取
// int data = 0;
// while ((data = fr.read()) != -1) {//读取一个字符
// System.out.print((char) data);
// }//2.2用缓冲流char[] buf = new char[1024];int count = 0;while ((count = fr.read(buf)) != -1) {System.out.println(new String(buf, 0, count));}//3.关闭fr.close();//1.创建FileWriter对象FileWriter fw = new FileWriter("D:\\searchwork\\study\\JavaSE\\writerhello.txt");for (int i = 0; i < 10; i++) {
// fw.write(buf);//也可以fw.write("你好世界helloworld\n");fw.flush();}fw.close();}
}
/*
你好世界helloworld*/
字符缓冲流
- 缓冲流:BufferedReader/BufferedWriter
- 高效读写
- 支持输入换行符。
- 可一次写一行、读一行。
public class Demo20 {public static void main(String[] args) throws IOException {//1.创建缓冲流FileReader fr = new FileReader("D:\\searchwork\\study\\JavaSE\\writerhello.txt");BufferedReader br = new BufferedReader(fr);//2.读取//2.1第一方式char[] buf = new char[1024];int count = 0;while ((count = br.read(buf)) != -1) {System.out.print(new String(buf, 0, count));}//2.2一次读一行
// String line;
// while ((line = br.readLine()) != null) {
// System.out.println(line);
// }//3.关闭br.close();//1.创建缓冲流FileWriter fw = new FileWriter("D:\\searchwork\\study\\JavaSE\\writerhello.txt");BufferedWriter bw = new BufferedWriter(fw);//2.写入for (int i = 0; i < 10; i++) {bw.write("好好学习,天天向上");bw.newLine();bw.flush();}//3.关闭bw.close();}
}
/*
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld
你好世界helloworld*/
打印流
- PrintWriter:
- 封装了print()/println()方法,支持写入后换行,
- 支持数据原样打印
public class Demo22 {public static void main(String[] args) throws IOException {//1.创建打印流PrintWriter pw = new PrintWriter("D:\\searchwork\\study\\JavaSE\\writerhello.txt");//2.打印//数据原样打印,不像字节流,输入97,打印出来是a,pw.println(97);pw.println(true);pw.println(3.14);pw.println('a');//3.关闭pw.close();System.out.println("执行完毕");}
}
/*文件内容
97
true
3.14
a*/
转换流
- 桥转换流:InputStreamReader/OutputStreamWriter
- 可将字节流转换为字符流。需求,有点时候只提供字节流,而内容是字符流,常用于网络编程。
- 可设置字符的编码方式。
public class Demo24 {public static void main(String[] args) throws IOException {//1.创建InputStreamReader对象FileInputStream fis = new FileInputStream("D:\\searchwork\\study\\JavaSE\\writerhello.txt");InputStreamReader isr = new InputStreamReader(fis, "utf-8");//2.读取文件int data = 0;while ((data = isr.read()) != -1) {System.out.print((char) data);}//3.关闭isr.close();//1.创建InputStreamReader对象FileOutputStream fos = new FileOutputStream("D:\\searchwork\\study\\JavaSE\\writerhello.txt");OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");//2.写入for (int i = 0; i < 10; i++) {osw.write("成功!\n");osw.flush();}//3.关闭osw.close();}
}
/*
打印输出
好好学习,天天向上 x10
文件内容
成功! x10*/