Day21 I/O框架
第一节:流的概念
内存与存储设备之间传输数据的通道
数据需要借助流来传输
1.1流的分类
按方向(重点)
输入流:将<存储设备>中的内容读入到<内存>中
输出流:将<内存>中的内容写入到<存储设备>中。
按单位:
字节流:以字节为单位,可以读写所有数据 。
字符流:以字符为单位,只能读写文本数据 。
按功能:
节点流:具有实际传输数据的读写功能。
过滤流:在节点流的基础之上增强功能。
第二节:字节流
2.1字节流的父类(抽象类)
InputStream:字节输入流
输入方法:
public int read(){}
public int read(byte[] b){}
public int read(byte[] b,int off,int len){}
OutputStream:字节输出流
输出方法:
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b,int off,int len){}
2.2字节节点流
FileOutputStream:
public void write(byte[] b) //一次写多个字节,将b数组中所有字节,写入输出流。
FileInputStream:
public int read(byte[] b) //从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1。
2.3字节过滤流
缓冲流:BufferedOutputStream/BufferedInputStream
提高IO效率,减少访问磁盘的次数;
数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close。
字节流示例代码:
//创建了字节节点流
//绝对路径:F:\\1905\\1905所有内容\\代码\\Day21
//相对路径:与上面同理, 不过是相对项目的根目录下的路径
//如果想在根目录下使用文件夹,自行创建。然后将指定的文件完整路径写清
FileOutputStream fos = new FileOutputStream("Files\\Target.txt");
// fos.write(65);
// fos.write(66);
// fos.write(67);
//
// fos.write('C');
byte[] b = new byte[]{65,66,67,68,69};
fos.write(b);
//创建输入字节节点流
FileInputStream fis = new FileInputStream("Files\\Target.txt");
///每次读一个字节
// int n = fis.read();
// System.out.println((char)n);
//将字节读到指定数组中
byte[] b2 = new byte[1];
int result = 0;
// do{
// result = fis.read(b2);
// System.out.println(result);
// }while(result != -1);
// System.out.println("已到达文件末尾");
while(true){
result = fis.read(b2);
if(result == -1){
System.out.println("文件已到达末尾");
break;
}
System.out.println(result);
}
// for(int i = 0 ; i<b2.length;i++){
// System.out.println(b2[i]);
// }
//将指定内容输入到数组中,指定存入的下标以及长度
// byte[] b3 = new byte[4];
// fis.read(b3, 1, 3);
// for(int i = 0 ;i<b3.length;i++){
// System.out.println((char)b3[i]);
// }
字节过滤流示例代码:
//1.创建字节节点流
FileOutputStream fos = new FileOutputStream("Files\\Target.txt");
//2.字节过滤流
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write('A');
bos.write('B');
bos.write('C');
bos.write('D');
bos.write('E');
//刷新缓冲区,将缓冲区里的数据一次性输出到指定的文件中
//bos.flush();
//同理,也能flush缓冲区
bos.close();
//------------------BufferedInputStream
//创建字节节点流 输入流
FileInputStream fis = new FileInputStream("Files\\Target.txt");
//创建字节过滤流 输入流
BufferedInputStream bis = new BufferedInputStream(fis);
//缓冲区
byte[] b = new byte[4];
while(true){
//接收每次读到的内容个数
int count = bis.read(b);
System.out.println(count);
//返回-1,说明已到达文件尾部,没有内容了
if(count == -1){
break;
}
//循环办理缓冲区的内容,循环次数由,每次读到的个数决定!
//注意:如果不确定文件内容,直接使用缓冲区数组的长度决定打印次数!可能会造成最后一次打印出现上一次的部分结果!
for(int i = 0; i<count;i++){
System.out.print((char)b[i]);
}
System.out.println();
}
第三节:对象流
对象流:ObjectOutputStream/ObjectInputStream
增强了缓冲区功能
增强了读写8种基本数据类型和字符串功能
增强了读写对象的功能:
readObject() 从流中读取一个对象
writeObject(Object obj) 向流中写入一个对象
3.1使用对象流
若使用对象流,必须实现对象序列化: implements Serializable
否则运行会抛出异常:java.io.NotSerializableException
对象序列化细节:
必须实现Serializable接口。
必须保证其所有属性均可序列化。
transient修饰为临时属性,不参与序列化。
读取到文件尾部的标志:java.io.EOFException。
示例代码:
//创建字节节点流
FileOutputStream fos = new FileOutputStream("Files\\object.txt");
//创建对象过滤流
ObjectOutputStream oos = new ObjectOutputStream(fos);
//往文件写对象。前提是自定义的对象支持序列化
oos.writeObject(new Student("Tom",20,"男",100D,new Address()));
oos.writeObject(new Student("marry",22,"女",80D,new Address()));
oos.writeObject(new Student("Gavin",21,"男",50D,new Address()));
//刷新 提交
oos.flush();
//----------------将对象已经持久化存储在文件里。------------------------
//----------------将对象通过反序列化,读取文件里的对象--------
//创建字节节点流 输入
FileInputStream fis = new FileInputStream("Files\\object.txt");
//创建对象过滤流 输入
ObjectInputStream ois = new ObjectInputStream(fis);
for(;;){
try {
//通过反序列化实现对文件里的对象 做读入
Object obj = ois.readObject();
System.out.println(obj.toString());
} catch (EOFException e) {//对象输入流特殊性:到达尾部时,不是-1,而是EOFException。
System.out.println("已到达文件末尾!没有内容了!");
break;//break可以写在catch块里!
}
}
}
}
//自定义对象变成可序列化
class Student implements Serializable{
String name;
Integer age;
String sex;
Double score;
transient Address address;//如果某些属性不参与序列化。可以使用transient修饰为临时属性即可
public Student(String name, Integer age, String sex, Double score,Address address) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
this.address = address;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score+",Address = "+address + "]";
}
}
class Address{
String position;
String email;
}
第四节:字符编码
ISO-8859-1 收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。
UTF-8 针对Unicode的可变长度字符编码
GB2312 简体中文
GBK 简体中文、扩充
BIG5 台湾,繁体中文
当编码方式和解码方式不一致时,会出现乱码
示例:
String s = "你好世界abc123喆";
//把字符串转换为字节
byte[] b = s.getBytes();
for(int i = 0;i<b.length;i++){
System.out.println(b[i]);
}
//--------------以上内容,将字符串内容转为字节,出现错误!------------
//转换GBK
String s1 = new String(b,"GBK");
System.out.println(s1);
//转换 big5
String s2 = new String(b,"BIG5");
System.out.println(s2);
第五节:字符流
字符流的父类(抽象类)
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){}
5.1字符节点流
FileWriter:
public void write(String str) //一次写多个字符,将b数组中所有字符,写入输出流。
FileReader:
public int read(char[] c) //从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回-1。
示例:
//创建了字符节点流
Writer w = new FileWriter("Files\\chars.txt");
w.write("HelloWorld");
w.write("HelloWorld");
w.write("abc");
w.flush();
//----------------------------------------------
Reader r = new FileReader("Files\\chars.txt");
//定义char数组 接收输入的每个字符
char[] chars = new char[5];
//使用死循环,重复去文件中读取内容到缓冲区里
for(;;){
//由于缓冲区只有5个空间,所以每次读取只能拿到5个内容,所以需要多次执行read拿多次5个内容
int count = r.read(chars);
if(count == -1)break;
for(int i = 0;i<count;i++){
System.out.print(chars[i]);
}
System.out.println();
}
}
5.2字符过滤流
缓冲流:BufferedWriter/BufferedReader
支持输入换行符。
可一次写一行、读一行。
PrintWriter:
封装了print() / println()方法,支持写入后换行。
示例:
//1.先有字符字节流
Writer w = new FileWriter("Files\\b.txt");
//2。创建字符过滤流
//BufferedWriter bw = new BufferedWriter(w);
// bw.write("HelloWorld");
// bw.newLine(); // ==== \n
// bw.write("dadadadada");
// bw.flush();
//PrintWriter类 与之前使用的打印语句 毫无差别!
//相比BufferedWriter,使用上来说更便捷。
PrintWriter print = new PrintWriter("Files\\b.txt");
print.print("HelloWolrd");
print.println("dadadadadadadadadada");//=====bw.write()之后bw.newLine();
print.flush();
//--------------------------------------------------
Reader r = new FileReader("Files\\b.txt");
BufferedReader br = new BufferedReader(r);
System.out.println(br.readLine());//能直接读取一行内容
System.out.println(br.readLine());
System.out.println(br.readLine());//当读取的行没有数据,返回NULL
}
5.3桥转换流
InputStreamReader/OutputStreamWriter
可将字节流转换为字符流。
可设置字符的编码方式。
示例:
//创建字节节点流
FileOutputStream fos = new FileOutputStream("Files\\convet.txt");
//创建 将字节节点流转换为字符节点流。
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
//接着包装, 创建字符过滤流
PrintWriter pw = new PrintWriter(osw);
pw.print('A');
pw.print(65);//不再将65作转换, 直接当成字符串
pw.println("哒哒哒哒哒哒哒哒");
pw.println("游戏开心为主");
pw.println("Night Life");
pw.println("温存");
pw.flush();
//---------------------------------------输入-------------------------
FileInputStream fis = new FileInputStream("Files\\convet.txt");//字节
InputStreamReader isr = new InputStreamReader(fis);//字符
//PrintWriter只跟BufferedWriter有关系。
//正常使用字符的过滤流 还是要使用BufferedReader
BufferedReader br = new BufferedReader(isr);//字符过滤
for(;;){
String s = br.readLine();
if(s == null){
break;
}
System.out.println(s);
}
5.4总结使用步骤:
创建节点流
[创建过滤流 设置字符编码集]
封装过滤流
读写数据
关闭流
ileInputStream(“Files\convet.txt”);//字节
InputStreamReader isr = new InputStreamReader(fis);//字符
//PrintWriter只跟BufferedWriter有关系。
//正常使用字符的过滤流 还是要使用BufferedReader
BufferedReader br = new BufferedReader(isr);//字符过滤
for(;😉{
String s = br.readLine();
if(s == null){
break;
}
System.out.println(s);
}
### 5.4总结使用步骤:
```java
创建节点流
[创建过滤流 设置字符编码集]
封装过滤流
读写数据
关闭流