之前的练习,我们一直把异常抛出,而实际开发中并不能这样处理,建议使用try...catch...finally
代码块,处理异常部分,代码使用演示:
public class Test {
public static void main(String[] args) {
// jdk7前: try...catch...finally处理
FileInputStream fis = null;
FileOutputStream fos = null;
try{
// 1.创建字节输入流对象,关联数据源文件路径
fis = new FileInputStream("day1\\aaa\\hb.jpg");
// 2.创建字节输出流对象,关联目的地文件路径
fos = new FileOutputStream("day1\\aaa\\hbCopy1.jpg");
// 3.定义一个byte数组,用来存储读取到的字节数据
byte[] bys = new byte[8192];
// 3.定义一个int变量,用来存储读取到的字节个数
int len;
// 4.循环读取
while ((len = fis.read(bys)) != -1) {
// 5.在循环中,写出字节数据
fos.write(bys,0,len);
}
}catch (Exception e){
}finally {
// 正常情况永远都会执行,一般用来释放资源
// 6.关闭流,释放资源
try {
if (fos != null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
还可以使用JDK7优化后的try-with-resource
语句,该语句确保了每个资源在语句结束时自动关闭。所谓的资源(resource)是指在程序完成后,必须关闭的对象。
格式:
try (创建流对象语句,如果多个,使用';'隔开) {
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
代码使用演示:
public class Test {
public static void main(String[] args) {
// jdk7: try...with...resource
try(
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day11\\aaa\\hb.jpg");
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day11\\aaa\\hbCopy2.jpg");
){
// 3.定义一个byte数组,用来存储读取到的字节数据
byte[] bys = new byte[8192];
// 3.定义一个int变量,用来存储读取到的字节个数
int len;
// 4.循环读取
while ((len = fis.read(bys)) != -1) {
// 5.在循环中,写出字节数据
fos.write(bys,0,len);
}
// 6.关闭流,释放资源--->会自动关闭,不需要手动关闭
// fos.close();
// fis.close();
}catch (Exception e){
}
}
}
概述:
构造方法
public Properties()创建一个空的属性集对象
存储方法
public Object setProperty(String key, String value) 保存一对属性。
public String getProperty(String key) 使用此属性列表中指定的键搜索属性值。
public Set<String> stringPropertyNames() 所有键的名称的集合。
public class Test1_与存储相关的方法 {
public static void main(String[] args) {
// 创建Properties对象
Properties prop = new Properties();
// 添加键值对
prop.setProperty("k1","v1");
prop.setProperty("k2","v2");
prop.setProperty("k3","v3");
prop.setProperty("k4","v4");
// 获取所有的键
Set<String> keys = prop.stringPropertyNames();
// 遍历所有的键,根据键找值
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key+" = "+value);
}
}
}
通过流对象,可以关联到某文件上,针对键值对在属性集与文本之间做存取键值对数据的操作。
存储或读取的文本内容格式:键=值(每行一对数据)
与流相关的方法
public void load(InputStream is);从字节输入流加载配置文件中的键值对,存储到Properties对象中
public void load(Reader r);从字符输入流加载配置文件中的键值对,存储到Properties对象中
public void store(OutputStream out,String comments);
用字节输出流写出键值对
public void store (Writer writer,String comments);
用字符输出流写出键值对
注意:
如果文件中有中文,就使用第二个load方法
案例:
public class Test2_与流相关的方法 {
public static void main(String[] args) throws Exception {
// 创建Properties对象
Properties prop = new Properties();
// 调用load方法加载文件中的键值对
prop.load(new FileInputStream("day1\\aaa\\a.txt"));// 读中文会乱码
// prop.load(new FileReader("day1\\aaa\\a.txt"));
// 打印输出
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key + " = " + prop.getProperty(key));
}
Properties pp = new Properties();
FileOutputStream fos = new FileOutputStream("demo_01\\aaa\\a.properties");
pp.setProperty("k1","v1");
pp.setProperty("k2","v2");
pp.setProperty("k3","v3");
pp.setProperty("k4","v4");
pp.store(fos,"Lyon");
}
}
配置文件中的数据:
k1=v1
k2=v2
k3=v3
k4=v4
高效读写
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强与包装,所以也是4个流,按照数据类型分类:
BufferedInputStream
,BufferedOutputStream
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
构造方法
public BufferedInputStream(InputStream is);
public BufferedOutputStream(OutputStream os);
拷贝文件效率测试
注意: 字节缓冲流没有特有的功能,读和写的功能都来自于他们的父类(InputStream , OutputStream)
普通字节流一次读写一个字节拷贝文件
public class Test1_普通字节流一次读写一个字节拷贝文件 {
public static void main(String[] args) throws Exception{
// 0.获取拷贝开始之前的时间
long start = System.currentTimeMillis();
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\aaa\\jdk9.exe");
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\bbb\\jdk9Copy1.exe");
// 3.定义一个int变量,用来存储读取到的字节数据
int len;
// 4.循环读取
while ((len = fis.read()) != -1) {
// 5.在循环中,写出字节数据
fos.write(len);
}
// 6.关闭流,释放资源
fos.close();
fis.close();
// 7.获取拷贝结束之后的时间
long end = System.currentTimeMillis();
// 8.打印输出
System.out.println("花了:"+(end - start)+"毫秒");// 至少十几分钟
}
}
字节缓冲流一次读写一个字节拷贝文件
public class Test2_字节缓冲流一次读写一个字节拷贝文件 {
public static void main(String[] args) throws Exception{
// 0.获取拷贝开始之前的时间
long start = System.currentTimeMillis();
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\aaa\\jdk9.exe");
BufferedInputStream bis = new BufferedInputStream(fis);
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\bbb\\jdk9Copy2.exe");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 3.定义一个int变量,用来存储读取到的字节数据
int len;
// 4.循环读取
while ((len = bis.read()) != -1){
// 5.在循环中,写出数据
bos.write(len);
}
// 6.关闭流,释放资源
bos.close();
bis.close();
// 7.获取拷贝结束之后的时间
long end = System.currentTimeMillis();
// 8.打印输出
System.out.println("花了:"+(end - start)+"毫秒");// 大概28秒
}
}
public class Test3_字节缓冲流一次读写一个字节数组拷贝文件 {
public static void main(String[] args) throws Exception{
// 0.获取拷贝开始之前的时间
long start = System.currentTimeMillis();
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\aaa\\jdk9.exe");
BufferedInputStream bis = new BufferedInputStream(fis);
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\bbb\\jdk9Copy3.exe");
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 3.定义一个byte数组,用来存储读取到的字节数据
byte[] bys = new byte[8192];
// 3.定义一个int变量,用来存储读取到的字节个数
int len;
// 4.循环读取
while ((len = bis.read(bys)) != -1){
// 5.在循环中,写出数据
bos.write(bys,0,len);
}
// 6.关闭流,释放资源
bos.close();
bis.close();
// 7.获取拷贝结束之后的时间
long end = System.currentTimeMillis();
// 8.打印输出
System.out.println("花了:"+(end - start)+"毫秒");// 大概3秒
}
}
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
字符缓冲流的构造方法
public BufferedReader(Reader r);创建一个字符缓冲输入流对象
public BufferedWriter(Writer w);创建一个字符缓冲输出流对象
字符缓冲流的特有方法
BufferedReader类继承Reader类,所以也拥有了Reader类中的所有方法,但自己还有特有的方法:
public String readLine(); 读取一行数据,读取到文件的末尾返回null
文件中的数据:
看这风景美如画
本想吟诗赠天下
奈何本人没文化
一句我操浪好大
public class Test1_BufferedReader类 {
public static void main(String[] args) throws Exception {
// 1.创建字符缓冲输入流对象,关联数据源文件路径
FileReader fr = new FileReader("day1\\aaa\\b.txt");
BufferedReader br = new BufferedReader(fr);
// 2.读数据
// 定义一个String类型的变量,用来存储读取到的行数据
String line;
// 循环读取
while ((line = br.readLine()) != null) {
System.out.println("line:" + line);
}
// 3.关闭流,释放资源
br.close();
}
}
BufferedWriter类继承Writer类,所以也拥有了Writer类中的所有方法,但自己还有特有的方法:
public void newLine(); 写一个行分隔符由系统属性定义符号
public class Test2_BufferedWriter类 {
public static void main(String[] args) throws Exception{
// 1.创建字符缓冲输出流对象,关联目的地文件路径
FileWriter fw = new FileWriter(“day1\aaa\c.txt”);
BufferedWriter bw = new BufferedWriter(fw);
// 2.写出数据
bw.write("看这风景美如画");
bw.newLine();
bw.write("本想吟诗赠天下");
bw.newLine();
bw.write("奈何本人没文化");
bw.newLine();
bw.write("一句我操浪好大");
// 3.关闭流,释放资源
bw.close();
}
}
请将文本信息恢复顺序。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
思路:
1.创建ArrayList集合,限制元素的类型为String
2.创建字符缓冲输入流对象,关联数据源文件路径
3.定义一个String类型的变量,用来存储读取到的行数据
4.循环读取
5.在循环中,把读取到的行数据存储到ArrayList集合中
6.关闭流,释放资源
7.使用Collections的sort方法对集合元素进行升序排序
8.创建字符缓冲输出流对象,关联目的地文件路径-->清空文件数据
9.循环遍历ArrayList集合
10.在循环中,写入集合元素(一行数据),换行
11.关闭流,释放资源
public class Test {
public static void main(String[] args) throws Exception {
//思路:
//1.创建ArrayList集合,限制元素的类型为String
ArrayList<String> list = new ArrayList<>();
//2.创建字符缓冲输入流对象,关联数据源文件路径
FileReader fr = new FileReader("day1\\aaa\\d.txt");
BufferedReader br = new BufferedReader(fr);
//3.定义一个String类型的变量,用来存储读取到的行数据
String line;
//4.循环读取
while ((line = br.readLine()) != null) {
//5.在循环中,把读取到的行数据存储到ArrayList集合中
list.add(line);
}
//6.关闭流,释放资源
br.close();
//7.使用Collections的sort方法对集合元素进行升序排序
Collections.sort(list);
//8.创建字符缓冲输出流对象,关联目的地文件路径-->清空文件数据
FileWriter fw = new FileWriter("day1\\aaa\\d.txt");
BufferedWriter bw = new BufferedWriter(fw);
//9.循环遍历ArrayList集合
for (String e : list) {
//10.在循环中,写入集合元素(一行数据),换行
bw.write(e);
bw.newLine();
}
//11.关闭流,释放资源
bw.close();
}
}
转换编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
Character Encoding
: 就是一套自然语言的字符与二进制数之间的对应规则。Charset
:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。
FileReader读取utf8编码的文件,中文不会乱码---->idea默认是utf8
FileReader读取gbk编码的文件,中文就会乱码
public class Test {
public static void main(String[] args) throws Exception {
// 创建FileReader对象,关联数据源文件路径
FileReader fr = new FileReader("day1\\ccc\\gbk.txt");// 乱码
//FileReader fr = new FileReader("day1\\ccc\\utf8.txt");// 不乱码
// 定义一个int变量,用来存储读取到的字符数据
int c;
// 循环读取
while ((c = fr.read()) != -1) {
// 在循环中,打印输出
System.out.println("字符:" + (char) c);
}
// 关闭流,释放资源
fr.close();
}
}
概述: java.io.InputStreamReader类继承Reader类,所以也是字符输入流,可以用来读字符数据
作用:
构造方法:
public InputStreamReader(InputStream is);创建一个转换输入流对象,使用默认字符集
public InputStreamReader(InputStream is,String charsetName);创建一个转换输入流对象,指定字符集
------>掌握
指定编码读取
读gbk编码文件
public class Test2_读gbk编码文件 {
public static void main(String[] args) throws Exception {
// 创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\ccc\\gbk.txt");
// 创建转换输入流对象,指定编码为gbk
InputStreamReader isr = new InputStreamReader(fis,"gbk");
// 定义一个int变量,用来存储读取到的字符数据
int c;
// 循环读取
while ((c = isr.read()) != -1) {
// 在循环中,打印输出
System.out.println("字符:" + (char) c);
}
// 关闭流,释放资源
isr.close();
}
}
读utf8编码文件
public class Test3_读utf8编码文件 {
public static void main(String[] args) throws Exception {
// 创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream(“day1\ccc\utf8.txt”);
// 创建转换输入流对象,指定编码为gbk
InputStreamReader isr = new InputStreamReader(fis,“utf8”);
// 定义一个int变量,用来存储读取到的字符数据
int c;
// 循环读取
while ((c = isr.read()) != -1) {
// 在循环中,打印输出
System.out.println("字符:" + (char) c);
}
// 关闭流,释放资源
isr.close();
}
}
概述: java.io.OutputStreamWriter类继承Writer类,所以也是字符输出流,可以用来写字符数据
作用:
构造方法:
public OutputStreamWriter(OutputStream os);创建转换输出流对象,使用默认字符集
public OutputStreamWriter(OutputStream os,String charsetName);创建转换输出流对象,指定字符集
------>掌握,常用指定编码写数据
指定gbk编码写出数据
public class Test1_指定gbk编写写数据 {
public static void main(String[] args) throws Exception{
// 创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\ccc\\gbk_1.txt");
// 创建转换输出流对象,指定gbk编码
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
// 写数据
osw.write("中国你好");
// 关闭流,释放资源
osw.close();
}
}
指定utf8编码写出数据
public class Test2_指定utf8编写写数据 {
public static void main(String[] args) throws Exception{
// 创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\ccc\\utf8_1.txt");
// 创建转换输出流对象,指定gbk编码
OutputStreamWriter osw = new OutputStreamWriter(fos,"utf8");
// 写数据
osw.write("中国你好");
// 关闭流,释放资源
osw.close();
}
}
public class Test {
public static void main(String[] args) throws Exception{
//思路:
//1.创建转换输入流对象,指定gbk编码
FileInputStream fis = new FileInputStream("day1\\ccc\\gbk.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");
//2.创建转换输出流对象,指定utf8编码
FileOutputStream fos = new FileOutputStream("day1\\ccc\\gbk_utf8.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"utf8");
//3.定义一个int变量,用来存储读取到的字符数据
int len;
//4.循环读取
while ((len = isr.read()) != -1) {
//5.在循环中,写出数据
osw.write(len);
}
//6.关闭流,释放资源
osw.close();
isr.close();
}
}
持久化存储对象
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据
、对象的类型
和对象中存储的属性
等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据
、对象的类型
和对象中存储的数据
信息,都可以用来在内存中创建对象。
概述: java.io.ObjectOutputStream类继承OutputStream,所以是一个字节输出流,可以用来写出字节数据,并且可以写对象
构造方法
public ObjectOutputStream(OutputStream out);创建序列化流对象,传入字节输出流
序列化操作---->写对象到文件中,变成字节数据
public final void wirteObject(Object obj);写一个对象(序列化操作)
注意:对象要想序列化要满足两个条件
被序列化的对象所属的类一定要实现Serializable接口(标记接口)
属性需要可序列化,如果某属性不想序列化,需注明瞬态transient关键字修饰
案例:
public class Person implements Serializable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test1 {
public static void main(String[] args) throws Exception{
// 序列化操作
// 1.创建Person对象
Person p = new Person("张三",18);
// 2.创建序列化流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\ddd\\a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 3.序列化对象
oos.writeObject(p);
// 4.关闭流,释放资源
oos.close();
}
}
概述: java.io.ObjectInputStream类继承InputStream,所以是一个字节输入流,可以用来读字节数据,并且可以读对象
构造方法
public ObjectInputStream(InputStream in);创建反序列化流对象,传入字节输入流
反序列化操作
public Object readObject();重构一个对象
案例:
public class Test {
public static void main(String[] args) throws Exception{
// 1.创建反序列化流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\ddd\\a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
// 2.重构对象
Object obj = ois.readObject();
// 3.关闭流,释放资源
ois.close();
// 4.打印对象
System.out.println(obj.toString());
}
}
序列化的注意事项
被序列化的对象所属的类一定要实现Serializable接口(标记接口)
被序列化的对象所有的属性也是要可以被序列化的
如果被序列化的对象的属性不想被序列化,那么该属性就需要使用transient关键字修饰,表示瞬态
public class Person implements Serializable {
String name;
transient int age;// 不会被序列化
//Pet pet;// Pet类一定要实现Serializable序列化接口,否则序列化失败
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
反序列化的注意事项
1.如果要反序列化成功,一定要能够找到该类的class文件,否则反序列化会失败,
报ClassNotFoundException 异常
2.如果能找到该类的class文件,但序列化后又修改了类,这个时候也会反序列化失败–>解决加版本号
报InvalidClassException异常
serializable接口给需要序列化的类,提供了一个序列版本号的静态常量serialVersionUID。该常量目的在于验证序列化对象和对应类是否版本匹配
public class Person implements Serializable {
static final long serialVersionUID = 2L;// 版本号
String name;
int age;
// String sex;不加版本号,序列化后增加属性,反序列化失败;加版本号,就反序列化成功
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
list.txt
文件中。list.txt
,并遍历集合,打印对象信息。Person类
public class Person implements Serializable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
序列化
public class Test1_序列化 {
public static void main(String[] args) throws Exception{
// 1.创建Person对象
Person p1 = new Person("张三",18);
Person p2 = new Person("李四",28);
Person p3 = new Person("王五",38);
Person p4 = new Person("赵六",48);
// 2.创建ArrayList集合,限制集合元素的类型为Person
ArrayList<Person> list = new ArrayList<>();
// 3.添加Person对象到集合中
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
// 4.创建序列化流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day1\\ddd\\list.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 5.序列化集合对象
oos.writeObject(list);
// 6.关闭流,释放资源
oos.close();
}
}
反序列化
public class Test2_反序列化 {
public static void main(String[] args) throws Exception{
// 1.创建反序列化流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day1\\ddd\\list.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
// 2.重构对象
ArrayList<Person> list = (ArrayList<Person>) ois.readObject();
// 3.关闭流,释放资源
ois.close();
// 4.循环遍历集合,打印输出
for (Person p : list) {
System.out.println(p);
}
}
}
概述: java.io.PrintStream类继承OutputStream,也是一个字节输出流,可以用来写出字节数据
作用: 可以方便打印输出各种类型的数据
使用:
构造方法:
public PrintStream(String fileName);创建一个打印流对象,通过参数关联目的地文件路径
成员方法:
public void print(任意类型);打印任意类型的数据到目的地文件中,打印完不换行
public void println(任意类型);打印任意类型的数据到目的地文件中,打印完换行
案例:
public class Test {
public static void main(String[] args) throws Exception{
// 1.创建打印流对象,关联目的地文件路径
PrintStream ps = new PrintStream("day1\\eee\\a.txt");
// 2.调用println()方法打印数据
ps.println(97);
ps.println("中国");
ps.println(3.14);
ps.println(true);
ps.println('a');
// 3.关闭流,释放资源
ps.close();
}
}
97
中国
3.14
true
a
```
装饰模式指的是在不改变原类, 不使用继承的基础上,动态地扩展一个对象的功能。
装饰模式遵循原则:
public interface Star {
public void sing();
public void dance();
}
public class Man implements Star {
@Override
public void sing() {
System.out.println("张三在唱忘情水...");
}
@Override
public void dance() {
System.out.println("张三在跳街舞...");
}
}
在不改变原类,不继承重写的基础上对Man类的sing方法进行扩展,dace方法不扩展
// 装饰类
public class ManWrapper implements Star{
Man m;
public ManWrapper(Man m) {
this.m = m;
}
@Override
public void sing() {
// 扩展增强
System.out.println("张三在唱忘情水...");
System.out.println("张三在唱冰雨...");
System.out.println("张三在唱笨小孩...");
}
@Override
public void dance() {
// 不需要扩展增强---->Man里面的dance方法要执行
m.dance();
}
}
public class Test {
public static void main(String[] args) {
// 需求:在不改变原类,不继承重写的基础上对Man类的sing方法进行扩展,dace方法不扩展
/*
1.被装饰类和装饰类必须实现相同的接口
2.在装饰类中必须传入被装饰类的引用
3.在装饰类中对需要扩展的方法进行扩展
4.在装饰类中对不需要扩展的方法调用被装饰类中同名的方法
*/
Man m = new Man();
ManWrapper mw = new ManWrapper(m);
mw.sing();
mw.dance();
}
}
commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以挺提高IO功能开发的效率。commons-io工具包提供了很多有关io操作的类,见下表:
包 | 功能描述 |
---|---|
org.apache.commons.io | 有关Streams、Readers、Writers、Files的工具类 |
org.apache.commons.io.input | 输入流相关的实现类,包含Reader和InputStream |
org.apache.commons.io.output | 输出流相关的实现类,包含Writer和OutputStream |
org.apache.commons.io.serialization | 序列化相关的类 |
步骤:
- public static int copy(InputStream in, OutputStream out); 把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以下)
- public static long copyLarge(InputStream in, OutputStream out);把input输入流中的内容拷贝到output输出流中,返回拷贝的字节个数(适合文件大小为2GB以上)
文件复制案例演示:
public class Test1_IOUtils类 {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("day1\\aaa\\hb.jpg");
FileOutputStream fos = new FileOutputStream("day1\\eee\\hbCopy1.jpg");
IOUtils.copy(fis,fos);
fos.close();
fis.close();
}
}
- public static void copyFileToDirectory(final File srcFile, final File destFile) //复制文件到另外一个目录下。
- public static void copyDirectoryToDirectory( File file1 ,File file2 );//复制file1目录到file2位置。
案例演示:
public class Test2_FileUtils {
public static void main(String[] args) throws Exception{
// 拷贝文件到文件夹
File srcF = new File("day1\\aaa\\hb.jpg");
File destF = new File("day1\\eee");
FileUtils.copyFileToDirectory(srcF,destF);
}
}
public class Test3_FileUtils {
public static void main(String[] args) throws Exception{
// 拷贝文件夹到文件夹
File srcF = new File("day1\\aaa");
File destF = new File("day1\\eee");
FileUtils.copyDirectoryToDirectory(srcF,destF);
}
}
1.IO异常的处理----jdk7前,jdk7
2.属性集-->加载配置文件数据,然后遍历
3.字节缓冲流高效拷贝文件; 字符缓冲流恢复文本顺序
4.转换流: 转换文件编码的案例
5.装饰者设计模式
6.commons-io--->拷贝文件,拷贝文件夹
- 能够使用Properties的load方法加载文件中配置信息
public Properties() :创建一个空的属性列表。
public void load(InputStream inStream): 从字节输入流中读取键值对。
public void load(Reader reader) 从字符输入流中读取键值对。
public Set<String> stringPropertyNames() :所有键的名称的集合。
public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
public Object setProperty(String key, String value) : 保存一对属性。
- 能够使用字节缓冲流读取数据到程序
BufferedInputStream: public BufferedInputStream(InputStream is);
使用InputStream中的读数据方法
- 能够使用字节缓冲流写出数据到文件
BufferedOutputStream: public BufferedOutputStream(OutputStream os);
使用OutputStream中的写数据方法
- 能够明确字符缓冲流的作用和基本用法
BufferedReader:
public BufferedReader(Reader r);
public String readLine();
BufferedWriter:
public BufferedWriter(Writer w);
public void newLine();
- 能够使用缓冲流的特殊功能
字节缓冲流:提高读写效率
字符缓冲流: 读一行,根据系统自动写换行
- 能够阐述编码表的意义
定义了字符和二进制数对应的规则
- 能够使用转换流读取指定编码的文本文件
InputStreamReader: public InputStreamReader(InputStream is,String charset)
- 能够使用转换流写入指定编码的文本文件
OutputStreamWriter: public OutputStreamWriter(OutputStream os,String charset)
- 能够使用序列化流写出对象到文件
ObjectOutputStream: public ObjectOutputStream(OutputStream os);
public void writeObject(Object obj);
- 能够使用反序列化流读取文件到程序中
ObjectInputStream: public ObjectInputStream(InputStream is);
public Object readObject();
- 能够理解装饰模式的实现步骤
1.装饰类和被装饰类需要实现同一个接口
2.装饰类中需要接收被装饰类的引用
3.在装饰类中对需要扩展的方法进行扩展
4.在装饰类中对不需要扩展的方法调用被装饰类中同名的方法
- 能够使用commons-io工具包