一、关于案例的几个注意事项
1.集合到文件数据排序改进版
(1)键盘你录入
(2)TreeSet集合根据学生的总成绩排序
(3)将集合中的学生信息写到文件中
问题:为什么 Scanner sc = new Scanner(System.in);要放在循环的里面?
//Scanner有一个小问题:先接受int类型的值,再接受String类型的值,会出问题
"\r\n"会占用String接受的数据
2.复制单级文件夹
单级文件夹:
就是该文件夹里面都是文件,没有文件夹
(1)注意事项
*文件夹 需要使用File类创建
*文件 需要使用File类创建
*文件内容 需要使用IO流
(2)思路
第一步:你必须在目的地创建一个和原文件夹名字一样的文件夹
第二步:把原文件夹下面所有的文件给复制到目的地新建的文件夹中
3.复制多级文件夹
(1)多级文件件:
就是该文件夹里面还有其他的文件夹
(2)思路
//找到要复制的那个多级文件夹
第一步:去目的地创建一个和该多级文件夹名字一样的文件夹
第二步:遍历原文件夹中的每一个文件对象
*文件对象是文件 isFile()
复制到目的地文件夹中
*文件对象是文件夹 isDirectory()
递归刚开始的逻辑
/*去目的地创建一个和该多级文件夹名字一样的文件夹
遍历原文件夹中的每一个文件对象
*文件对象是文件 isFile()
复制到目的地文件夹中
*文件对象是文件夹 isDirectory()
*/
file.mkldir(); //同名文件夹
//遍历原来文件夹
for(File f : file.listFiles){
//如果是文件
if(f.isFile()){
copy
}else{
创建一个一模一样的文件夹
}
}
二、关于异常的处理方式
(1)try–catch—finally
//至少要掌握
(2)try -- with --resources
优点:不需要手动释放资源
缺点:在使用idea自动生成的时候,不能帮我们生成catch块
//这两种异常的处理方式不需要我们去记它的格式,一定要使用idea自动生成
三、标准流 //了解
1.标准输入流(System.in)
public static final InputStream in
(1)本质:字节输入流
(2)作用:用于接收控制台输入的数据
(3)注意事项:这个流是由JVM底层提供的,外界是模拟/创建不出来的
(4)以后在开发中怎么使用
Scanner sc = new Scanner(System.in);
2.标准输出流(System.out)
public static final PrintStream out
(1)本质:字节输出流
(2)作用:在控制台打印出数据
(3)以后在开发中怎么使用
*System.out.println(); //换行
*System.out.println(xxxx); //在控制台打印xxxx,然后再换行
*System.out.print(xxx); //在控制台打印xxx
四、打印流 //了解
//打印流只能是输出流,不能是输入流
1.字节打印流(PrintStream)
(1)构造方法
PrintStream(String fileName) 使用指定的文件名创建新的打印流,无需自动换行。
举例:PrintStream ps = new PrintStream(“day09/a.txt”);
(2)方法
*本身的方法(作为字节输出流继承在字节流的方法)
举例:
ps.write(97); // a 这里是把97进行了ASCII码转换
*特有方法
举例:
ps.print(97); // 97 这里是不会进行转码的
ps.println(97); // 97 并且在最后会换行
ps.println(); // 换行
2.字符打印流(PrintWriter)
(1)构造方法
*PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新。
举例:PrintWriter pw1 = new PrintWriter("day09/a");
*PrintWriter(Writer out, boolean autoFlush) 创建一个新的PrintWriter
//参数 Writer:字符输出流 boolean:如果为true,那么会自动刷新 如果为false,那么就不会自动刷新
举例:PrintWriter pw2 = new PrintWriter(new FileWriter("day09/a"),true);
(2)方法
*本身方法(作为字符流继承过来的方法)
举例:
pw1.write("xx");
*特有方法
pw1.println("xx"); <================> pw1.write("xx"); pw1.write("\r\n");
pw2.println("xx"); <================> pw1.write("xx"); pw1.write("\r\n"); pw.flush();
五、对象序列化流 //了解 一般在开发中基本不用,多用于代码的底层
1.什么是序列化?什么又是反序列化?
//扩展:数据的两种状态
(1)游离态数据
运行在程序中(内存)的数据(特点:程序关闭之后,再次打开数据就没了) //学生管理系统
(2)持久化数据
存储在硬盘上的数据(特点:程序关闭之后,再次打开的时候数据还在)//视频
(1)序列化(持久化)://☆☆☆☆☆
游离态数据(对象) ------------ 持久态数据(文件)
(2)反序列化: //☆☆☆☆☆
持久态数据(文件)------------ 游离态数据(对象)
2.相关的类(ObjectOutputStream)
(1)构造方法
ObjectOutputStream(OutputStream out)创建一个写入指定的OutputStream的ObjectOutputStream
*本质上是一个字节输出流
*参数:要传入的是具体的字节输出流对象
(2)相关方法
void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
//问题1: 使用序列化流将对象序列化到文件中,那么我打开该文件,能不能读懂文件?
不能读懂,因为你用的是字节流
//问题2:writeObject方法的参数是Object,那么如果我想一次性序列化多个对象该怎么办?
创建一个该对象的集合,然后把集合对象传递给writeObject
(3)应用场景
京东商城的购物车添加商品
3.Serializable接口
(1)特点
没有抽象方法,这样的接口称为标记接口
//标记接口的出现就是为了表明这个接口仅仅是起到了一个标记的作用, Serializable接口标记着实现这个接口的类可以被序列化
举例:菜市场猪肉上面有一个蓝色的戳,这个蓝色的戳就标记着这个猪肉是合格的
六、对象反序列化流
//持久态数据(文件)------------ 游离态数据(对象)
1.相关的类(ObjectInputStream)
(1)构造方法
ObjectInputStream(InputStream in) 创建从指定的InputStream读取的ObjectInputStream
*本质上是一个字节输入流
*要传入的是具体的字节输入流对象
(2)相关方法
Object readObject() 从ObjectInputStream读取一个对象
2.代码实现
public class Demo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day09/b.txt"));
Object o = ois.readObject();
Student o1 = (Student) o;
System.out.println(o1);
}
}
七、关于serialVersionUID和transient
1.serialVersionUID这个有什么用?
当我们修改了对象的所属的类文件时,反序列化不受影响
2.加上serialVersionUID和不加serialVersionUID有什么区别?
听课证(对象),在序列化的时候,在你的听课证上拍了一张你当时入学的照片(白色上衣+黑色裤子+安踏板鞋)
*不加serialVersionUID:在反序列化的时候,检查你的上衣、裤子、鞋子。上课第二天你穿了一双耐克的鞋子,那不让你上课。
*加上serialVersionUID:相当于在你的听课证上加了一个学号,检查的时候只是检查学号是否为这个班级的,只有是这个班的就可以来听课
3.怎么写这个serialVersionUID?
使用idea自动生成
ALT + enter ---------- 选择 Add "SerialVersionUID" Field
//具体的设置见图
4.怎么让字段不被序列化
在字段的前面加上关键字transient
5.实际举例
Idea设置字体(大小、颜色、字体类型)
当你关闭Idea的时候----------将字体的相关设置信息序列化到硬盘上
当你再次打开Idea的时候--------将硬盘上文件的内容反序列化到内存中
八、Properties //☆☆☆☆☆
1.作为Map集合使用
//不解释,和map集合的用法一模一样的
2.Properties的特有功能
(1)Object setProperty(String key,String value)设置集合的键和值,都是String类型,底层调用 Hashtable方法 put //相当于map集合的put方法
(2)String getProperty(String key) 使用此属性列表中指定的键搜索属性 // get(key)
(3)Set stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 // keySet()
3.properties集合和IO之间的结合
(1)void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)
//从文件中通过字节输入流读取内容 参数:字节输入流
代码实现:
public class Demo5 {
public static void main(String[] args) throws IOException {
Properties p1 = new Properties();
FileInputStream fis = new FileInputStream("day09/a.txt");
p1.load(fis); //使用字节输入流将文件中的内容读取到properties集合中
String age = p1.getProperty("age");
System.out.println(age);
}
}
(2)void load(Reader reader) 从输入字符流读取属性列表(键和元素对)
//从文件中通过字节输入流读取内容 参数:字符输入流
(3)void store(OutputStream out, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
代码实现:
public class Demo4 {
public static void main(String[] args) throws IOException {
Properties p1 = new Properties();
p1.setProperty("id","heima001");
p1.setProperty("name","zhangsan");
p1.setProperty("age","21");
p1.setProperty("school","chuanzhidaxue");
FileOutputStream fos = new FileOutputStream("day09/a.txt");
p1.store(fos,"测试store方法");
}
}
//运行结果:
age=21
school=chuanzhidaxue
name=zhangsan
id=heima001 //存储到文件中后,properties的key和value会使用 = 来分隔
(4)void store(Writer writer,String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用load(Reader)方法的格式写入输出字符流
4.练习:首先给出一个文件a.txt,首先读取到key为age的属性的值,如果age不等于30,那么将文件中age覆盖为23 //掌握
代码:
public class Demo6 {
public static void main(String[] args) throws IOException {
Properties p1 = new Properties();
FileInputStream fis = new FileInputStream("day09/a.txt");
p1.load(fis);
String age = p1.getProperty("age");
if (Integer.parseInt(age)!=30){
p1.setProperty("age","23");
FileOutputStream fos = new FileOutputStream("day09/a.txt"); //这行代码不能放在前面,因为执行这行代码的时候a.txt文件会被清空
p1.store(fos,"将age改为23");
}
}
}
5.关于properties想关联的文件中键值对之间的翻个符问题
在文件中,key和value的分隔符除了= ,还可以是 空格和冒号
name=zhangsan
age:23
id 001