File类 (day11)
IO流
IO流的概述和分类
字节流
字符流
其他流
字符流 (day12)
转换流
对象操作流
Properties
01. 字节流操作文本文件出现乱码问题
使用字节流读写带中文数据的文件, 会出现什么问题?
中文乱码
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//读取带有中文的文件
FileInputStream fis = new FileInputStream("day12\\Demo01.txt");
int b;
while ((b = fis.read()) != -1){
System.out.println((char)b);
//中文乱码
}
fis.close();
}
}
02. 字符流-编码表
了解内容1
计算机中存储的信息都是以二进制数表示的
编码: 按照某种规则, 将字符变为二进制, 再存储到计算机中
解码: 按照同样的规则, 将存储在计算机中的二进制数解析显示出来
编码和解码的方式如果不统一, 会造成乱码问题
了解内容2
ASCII码表: 每个信息交换标准代码, 包含了数字, 大小写字母和常见标点符号(不包含中文)
GBK码表: windows系统默认的码表, 兼容ASCII, 包含了21003个汉字并支持繁体字以及部分日韩文字
在GBK码表中, 一个中文占两个字节
Unicode码表: 被称为万国码, 计算机科学领域的一项业界标准, 容纳世界上大多数国家的常见文字和符号
了解内容3
由于要表示的字符太多, 所以Unicode码表中的数据不是以二进制的形式直接存储的
会通过UTF-7,UTF-7.5,UTF-8,UTF-16,UTF-32等进行编码, 然后再存储到计算机, 其中最为常见的是UTF-8
在Unicode万国码中, 以UTF-8编码后一个中文占三个字节
总结
ASCII -> 各个国家的(GBK,EUC-KR,Shift_JIS) -> 统一 -> Unicode
Windows默认的编码是GBK, 支持中文, 一个中文占2个字节
以后我们使用Unicode的UTF-8只是一种编码方式, 不是编码表, 支持中文, 一个中文占3个字节
03. 字符流-编码和解码的方法
String字符串中, 编码和解码的方法
1.编码
byte[] getBytes(); 使用平台默认的字符集将String编码为字节, 返回字节数组
byte[] getBytes(String charsetName); 使用指定的字符集将String编码为字节, 返回字节数组
2.解码
String(byte[] bytes); 使用平台默认的字符集解码字节数组, 构造成新的字符串
String(byte[] bytes, String charsetName); 使用指定的字符集解码字节数组, 构造成新的字符串
再次记忆!
windows默认采用编码表 -> GBK -> 支持中文, 一个中文占3个字节
IDEA默认采用编码方式 -> Unicode表中的UTF-8编码方式, 一个中文占2个字节
代码示例
public class Demo {
public static void main(String[] args) throws UnsupportedEncodingException {
/*
解码
*/
String s = "道北吴彦祖";
byte[] bytes1 = s.getBytes();
System.out.println(Arrays.toString(bytes1)); //IDEA默认UT8, 一个中文占3字节
//[-23, -127, -109, -27, -116, -105, -27, -112, -76, -27, -67, -90, -25, -91, -106]
byte[] bytes2 = s.getBytes("GBK"); //windows默认GBK, 一个中文占2字节
System.out.println(Arrays.toString(bytes2));
//[-75, -64, -79, -79, -50, -30, -47, -27, -41, -26]
/*
编码
*/
byte[] b1 = new byte[]{-23, -127, -109, -27, -116, -105, -27, -112, -76, -27, -67, -90, -25, -91, -106};
String s1 = new String(b1);
System.out.println(s1); //道北吴彦祖
byte[] b2 = new byte[]{-75, -64, -79, -79, -50, -30, -47, -27, -41, -26};
String s2 = new String(b2);
System.out.println(s2); //����������
// 为什么乱码?? 因为这个b2数组, 是26行通过GBK解码得来的. 现在通过IDEA默认的UT8进行编码, 字符集不统一
// 怎么解决?? 构造新String时参数指定字符串为GBK即可
String s3 = new String(b2,"GBK");
System.out.println(s3); //道北吴彦祖
}
}
04. 字节流读取中文出现乱码的原因
为什么通过"字节流"读写中文会出现乱码?
因为字节流一次读一个字节, 而不管是GBK还是UT8, 一个中文占多个字节, 字节流一次只读取了中文的一部分
05. 字符流-读取中文的过程
字符流本质
字符流 = 字节流 + 编码表
无论在哪张码表中
中文的第一个字节一定是: 负数
字符流读取中文的过程
当字符流读数据时, 读到了负数的字节就知道读到了中文
再去看使用的什么码表, 决定一次读几个字节 (GBK中2个, UTF-8中3个)
技术选型(应用场景)
1. 拷贝文件 -> 字节流/字节缓冲流
2. 读取文本文件中的数据到内存 -> 字符输入流FileInputStream.read
3. 将内存中的数据写入文本文件 -> 字符输出流FileOutputStream.write
06. 字符流-写出数据 -------------------- 字符流写数据
字符输出流构造
FileWriter(File对象);
FileWriter(字符串路径);
字符流写数据的5种方式
1. void write(int c); 写一个字符
2. void write(char[] cbuf); 写一个字符数组
3. void write(char[] cbuf, int off, int len); 写一个字符数组的一部分
4. void write(String str); 写一个字符串
5. void write(String str, int off, int len); 写一个字符串的一部分
字符流写数据步骤
1. 创建字符输出流对象
2. 写数据
3. 国际惯例
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//FileWriter fw = new FileWriter(new File("day12\\Demo02.txt"));
//传递路径作为构造参数, 底层会自动封装为File对象
FileWriter fw = new FileWriter("day12\\Demo02.txt");
//1. void write(int c); 写一个字符
//fw.write(97);
//fw.write(98);
//fw.write(99); //abc
char[] chars = {'d','e','f','g','h'};
//2. void write(char[] cbuf); 写一个字符数组
//fw.write(chars); //defgh
//3. void write(char[] cbuf, int off, int len); 写一个字符数组的一部分
//fw.write(chars,0,3); //def
String str = "123黑马程序员";
//4. void write(String str); 写一个字符串
//fw.write(str); //123黑马程序员
//5. void write(String str, int off, int len); 写一个字符串的一部分
fw.write(str,3,5); //黑马程序员
//3. 国际惯例
fw.close();
}
}
07. 字符流-写出数据的注意事项
字符流写数据的注意事项
1. 如果文件不存在, 会创建新的
2. 如果路径错误, 会报错
3. 如果文件存在, 先清空再写入
4. 构造第二个参数不写, 默认为false, 表示新数据会覆盖老数据 (先清空再写入) , 追加写入需要手动给true
5. 如果写出int类型的整数, 那么写出是该整数在码表对应的字符
6. 如果写出字符串, 是将该字符串本身原样写出
7. 必须释放资源
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//注意: 如果文件不存在, 会创建新的
FileWriter fw = new FileWriter("day12\\Demo03.txt");
//注意: 如果路径错误, 会报错
//FileWriter fw = new FileWriter("day12\\aaa\\Demo02.txt"); //java.io.FileNotFoundException(系统找不到指定的路径。)
//注意: 构造第二个参数不写默认为false, 表示新数据会覆盖老数据, 追加写入需要手动给true
//FileWriter fw = new FileWriter("day12\\Demo03.txt",true);
//注意: 如果文件存在, 先清空再写入
//fw.write("我是新数据");
fw.write(97); //a
// 如果就要写97怎么办
fw.write("97"); //97
//注意: 必须释放资源
fw.close();
}
}
08. 字符流-flush和close方法
flush和close方法
flush(); 刷新流, 刷新后还可以写数据
close(); 关闭流释放资源, 注意关闭前会先刷新流, 再关闭; 但是关闭后就不能继续写数据了
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day12\\Demo04.txt");
fw.write(97);
fw.flush(); //这里刷新后, 文件中只显示a
fw.write(98);
fw.flush(); //加上这里刷新后, 文件中才显示ab
fw.close();
//close(); 关闭流释放资源, 注意关闭前会先刷新流, 再关闭; 但是关闭后就不能继续写数据了
fw.write(100); //java.io.IOException: Stream closed
}
}
09. 字符流-读取数据 -------------------- 字符流读数据
字符流读数据步骤
1. 创建字符输入流对象
2. 读数据 (读一个)
3. 国际惯例
代码示例(一次读一个)
public class Demo01 {
public static void main(String[] args) throws IOException {
//1. 创建字符输入流对象
FileReader fr = new FileReader("day12\\Demo05.txt"); //如果文件不存在则报错
//2. 读数据 (读一个)
int ch;
while ((ch = fr.read()) != -1){
//读取每一个字节并打印
//System.out.print(ch + " "); //40657 39532 31243 24207 21592 54 54 54
//字节强转为字符
System.out.print((char) ch + " "); //黑 马 程 序 员 6 6 6
}
//3. 国际惯例
fr.close();
}
}
字符流读数据步骤
1. 创建字符输入流对象
2. 读数据 (读多个)
2.1 创建字符数组
2.2 定义len表示读到的有效字符个数
2.3 如果没到文件结尾就继续读
2.4 将读到的字符数组作为参数, 构造新的字符串
3. 国际惯例
代码示例
public class Demo02 {
public static void main(String[] args) throws IOException {
//1. 创建字符输入流对象
FileReader fr = new FileReader("day12\\Demo05.txt"); //如果文件不存在则报错
//2. 读数据 (读多个)
//2.1 创建字符数组
char[] chars = new char[1024];
//2.2 定义len表示读到的有效字符个数
int len;
//2.3 如果没到文件结尾就继续读
while ((len = fr.read(chars)) != -1) {
//2.4 将读到的字符数组作为参数, 构造新的字符串
System.out.println(new String(chars, 0, len));
}
//3. 国际惯例
fr.close();
}
}
10. 字符流-练习
练习需求:
将用户输入的username和password存入本地文件实现永久化存储
要求username和password各自独占一行
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//拿到用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名: ");
String username = sc.next();
System.out.println("请输入密码: ");
String password = sc.next();
//创建字符输出流对象
FileWriter fw = new FileWriter("day12\\Demo06.txt");
//写数据
fw.write(username);
//换行后再写数据
fw.write("\r\n");
fw.write(password);
//刷新流
fw.flush();
//国际惯例
fw.close();
}
}
11. 字符缓冲输入流-读取数据
字符缓冲流
BufferedWriter: 字符缓冲输出流, 可以高效的写出数据
BufferedReader: 字符缓冲输入流, 可以高效的读取数据
为什么缓冲流更高效?
和字节缓冲流底层一个道理, 都是提供了一个8K的缓冲区, 尽量让操作在内存中实现
代码示例(BufferedWriter: 字符缓冲输出流, 可以高效的写出数据)
public class Demo {
public static void main(String[] args) throws IOException {
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("day12\\Demo06.txt"));
// 读数据
char[] chars = new char[1024];
int len;
while ((len =br.read(chars)) != -1){
System.out.println(new String(chars,0,len));
}
//国际惯例
br.close();
}
}
12. 字符缓冲输出流-输出数据
代码示例(BufferedReader: 字符缓冲输入流, 可以高效的读取数据)
public class Demo {
public static void main(String[] args) throws IOException {
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("day12\\Demo07.txt"));
// 一次写一个字符, 整数对应表中的字符
//bw.write(97);
// 一次写一个字符数组
//bw.write(new char[]{'a','b','c'}); //abc
// 一次写一个字符数组的一部分
//bw.write(new char[]{'a','b','c'},0,2); //ab
// 一次写一个字符串
//bw.write("97"); //97
// 一次写一个字符串的一部分
// bw.write("黑马程序员666",0,5); //黑马程序员
//刷新流
bw.flush();
//国际惯例
bw.close();
}
}
13. 缓冲流-特有方法
缓冲流特有方法
1. BufferWriter: void newLine(); 底层匹配系统, 写一行分隔(换行)符
2. BufferReader: void String readLine(); 读一行文字, 不读取分隔(换行)符, 到达文件结尾为null
代码演示(BufferWriter: void newLine())
public class Demo01 {
public static void main(String[] args) throws IOException {
// 写数据
BufferedWriter bw = new BufferedWriter(new FileWriter("day12\\Demo08.txt"));
bw.write("黑马程序员");
bw.newLine();
bw.write("传智专修学院");
bw.newLine();
bw.write("-----------");
/*
黑马程序员
传智专修学院
-----------
*/
//国际惯例
bw.flush();
bw.close();
}
}
代码演示(BufferReader: void String readLine())
public class Demo02 {
public static void main(String[] args) throws IOException {
//读数据
BufferedReader br = new BufferedReader(new FileReader("day12\\Demo08.txt"));
//一次读一行
//System.out.println(br.readLine()); //黑马程序员
//System.out.println(br.readLine()); //传智专修学院
//System.out.println(br.readLine()); //-----------
//System.out.println(br.readLine()); //null
//标准读数据代码
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
/*
黑马程序员
传智专修学院
-----------
*/
}
//国际惯例
br.close();
}
}
14. 缓冲流-练习
练习需求: 读取文件中的数据, 排序后将数据写到本地文件
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//读数据
BufferedReader br = new BufferedReader(new FileReader("day12\\Demo09.txt"));
String line = br.readLine(); //6 5 7 9 2 1 3 4 8 10
br.close();
//根据空格切割
String[] srr = line.split(" ");
//排序
//Arrays.sort(srr);
//System.out.println(Arrays.toString(arr)); //[1, 10, 2, 3, 4, 5, 6, 7, 8, 9] 注意直接排序会按照字符串首字符升序
//创建整数数组, 将srr元素转为整数存入
int[] arr = new int[srr.length];
for (int i = 0; i < srr.length; i++) {
arr[i] = Integer.parseInt(srr[i]);
}
//排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//写数据
BufferedWriter bw = new BufferedWriter(new FileWriter("day12\\Demo10.txt"));
//遍历整数数组
for (int i = 0; i < arr.length; i++) {
//加入字符串空格, 同时转为字符串
bw.write(arr[i] + " "); //1 2 3 4 5 6 7 8 9 10
}
bw.flush();
bw.close();
}
}
15. IO流小结
IO流
流向分: 输入流(读)和输出流(写)
类型分: 字节流(拷贝)和字符流(读写文本数据)
字节流: 一个一个字节拷贝慢, 通过数组+底层的缓冲区提升(缓冲流)
1.FileInputStream: 字节输入流 -> BufferedInputStream: 字节缓冲输入流
2.FileOuputStream: 字节输出流 -> BufferedOuputStream: 字节缓冲输出流
字符流:
1.FileReader: 字符输入流 -> BufferedReader: 字符缓冲输入流 -> readLine()读一行
2.FileWriter: 字符输出流 -> BufferedWriter: 字符缓冲输出流 -> newLine()换行
16. 转换流-概念 -------------------- 其他流
什么是转换流?
可以将字符流和字节流相互转换
回忆字符流的底层?
字符流 = 字节流 + 编码表
InputStreamReader
从字节流 -> 字符流的桥梁, 使用指定的charset将"读到的字节解码为字符"
OutputStreamWriter:
从字符流 -> 字节流的桥梁, 使用指定的charset将"写入的字符编码为字节"
关系图示
文件 -> 字节流 -> 转换流InputStreamReader -> 字符流FileReader -> 内存
内存 -> 字节流 -> 转换流OutputStreamWriter -> 字符流FileWriter -> 文件
17. 转换流-指定编码读写
转换流的使用场景
JDK11之前: 指定编码读写
JDK11之后: 一般不会直接操作转换流了
代码示例(使用转换流读写数据)
public class Demo {
public static void main(String[] args) throws IOException {
//使用转换流, 按照指定charset读数据
InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\Administrator\\Desktop\\a.txt"), "GBK");
int ch;
while ((ch = isr.read()) != -1) {
System.out.print((char) ch + " "); //道 北 吴 彦 祖
}
isr.close();
//使用转换流, 按照指定charset写数据
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\b.txt"), "UTF-8");
osw.write("从IDEA中朝桌面写数据,指定字符集为UTF-8才不会乱码!");
osw.flush();
osw.close();
//注意: txt文本文档会自动改变字符集, 我们可以通过查看字节验证编码格式的改变, 这里了解即可!
}
//字符流读数据
private static void method01() throws IOException {
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\a.txt");
int ch;
while ((ch = fr.read()) != -1) {
System.out.print((char) ch + " "); //� � � � � � � Ա
/*
乱码问题
1. a.txt是在电脑桌面保存的, a.txt使用的是windows系统默认的编码表GBK中的ANSI编码格式
2. 我们在IDEA中写代码读取a.txt, IDEA默认使用是Unicode码表中的UTF-8编码格式
3. 编码和解码的编码格式不一致, 就会出现乱码!
*/
}
fr.close();
}
}
JDK11之后: 一般不会直接操作转换流了
因为FileReader在底层帮我们提供了一个新的构造, 可以直接指定Charset
Charset.for(字符集名称);
构造源码
Since 11 : 这个注释的意思代表, 该构造从JDK11开始可以使用
public FileReader(String fileName, Charset charset) throws IOException {
super(new FileInputStream(fileName), charset);
}
代码示例
public class Demo02 {
public static void main(String[] args) throws IOException {
// 使用字符输入流读数据(底层帮忙简化了转换流)
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\a.txt", Charset.forName("GBK"));
int ch;
while ((ch = fr.read()) != -1){
System.out.print((char) ch + " "); //道 北 吴 彦 祖
}
}
}
18. 对象操作流-基本特点
对象操作流特点?
可以将对象以字节的形式, 书写到本地文件, 直接打开文件是读不懂的
需要再次用对象操作流读到内存中
19. 对象操作流-序列化
对象操作流
1. 对象操作输入流 (对象反序列化流): ObjectInputStream
2. 对象操作输出流 (对象序列化流): ObjectOutputStream
oos.writeObject(对象名);
Serializable接口
1. 是一个标记性接口, 接口中没有提供任何抽象方法
2. 实现这个接口代表该类对象可以被序列化, 否则会报错
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//创建对象
User user = new User("张三","qwer");
//创建对象操作输出流 (对象序列化流): ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day12\\Demo11.txt"));
//写出对象数据: writeObject(对象名);
oos.writeObject(user);
//国际惯例
oos.close();
/*
文件中的内容:
�� sr )com.demo19_对象操作流_序列化.
User��u�sCԓ L namet Ljava/lang/String;
L passwordq ~ xpt 张三t qwer
*/
}
}
/*
如果改类对象需要序列化, 必须实现Serializable接口, 否则报错:
java.io.NotSerializableException: com.demo19_对象操作流_序列化.User
*/
class User implements Serializable {
private String name;
private String password;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
20. 对象操作流-反序列化
对象操作流
对象操作输入流 (对象反序列化流): ObjectInputStream
代码示例(读取上一个代码写出的Demo11.txt)
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//对象操作输入流 (对象反序列化流): ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day12\\Demo11.txt"));
//读数据
User user = (User) ois.readObject();
//打印对象
System.out.println(user); //打印对象出现地址? 怎么看属性?
}
}
21. 对象操作流-两个注意点1
我们使用序列化流写入一个对象数据, 假如后来修改了对象所属的类文件, 那么再次读该对象时会不会出现问题?
会的, 会报错
Exception in thread "main" java.io.InvalidClassException:
com.demo19_对象操作流_序列化.User; local class incompatible:
stream classdesc serialVersionUID = -4901757396016966509,
local class serialVersionUID = -3344419051753874665
serialVersionUID: 序列号
通过序列化流写入一个对象数据, 如果我们没有提供序列号, 系统会给一个
这个错误表示, 写入时的类中序列号和, 读取时的类中序列号不一样
如果出现问题, 该如何解决?
我们自己定义一个序列号即可
private static final long serialVersionUID = 1L;
如果一个对象中的某个成员变量的值, 不想被序列化, 应该怎么实现?
将该变量使用transient关键字修饰, 代表该变量就不参与序列化
private String name;
private transient String password; //该属性不参与序列化, 没有赋值那么写入文件为null
22. 对象操作流-两个注意点2
23. 对象操作流-练习
练习需求:
创建多个JavaBean对象到文件中, 再次读取到程序中
注意: 读取对象读到文件末尾, 不是-1, 而会报异常
解决方式1:
我们需要try...catch捕获异常, 然后结束while循环
解决方式2:
写对象时, 存入一个容器, 整体序列化这个容器即可
代码示例
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//实例化对象
Singer s1 = new Singer("周杰伦", 18);
Singer s2 = new Singer("林俊杰", 19);
Singer s3 = new Singer("潘玮柏", 20);
//解决方式2: 写对象时, 存入一个容器, 整体序列化这个容器即可
ArrayList<Singer> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
//写对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day12\\Demo13.txt"));
oos.writeObject(list);
oos.close();
//读对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day12\\Demo13.txt"));
ArrayList<Singer> newList = (ArrayList<Singer>) ois.readObject();
System.out.println(newList); //[Singer{name='周杰伦', age=18}, Singer{name='林俊杰', age=19}, Singer{name='潘玮柏', age=20}]
}
private static void method01() throws IOException, ClassNotFoundException {
//实例化对象
Singer s1 = new Singer("周杰伦", 18);
Singer s2 = new Singer("林俊杰", 19);
Singer s3 = new Singer("潘玮柏", 20);
//写对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day12\\Demo13.txt"));
oos.writeObject(s1);
oos.writeObject(s2);
oos.writeObject(s3);
oos.close();
//读对象
// ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day12\\Demo13.txt"));
// Object obj;
// while ((obj = ois.readObject()) != null){
// System.out.println(obj);
// /*
// Singer{name='周杰伦', age=18}
// Singer{name='林俊杰', age=19}
// Singer{name='潘玮柏', age=20}
// //数据是读到了, 但是当用readObject读到文件结尾, 会EOFException报错
// Exception in thread "main" java.io.EOFException:
// */
// }
//读对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day12\\Demo13.txt"));
Object obj;
//解决方式1: 我们需要try...catch捕获异常, 然后结束while循环
while (true) {
try {
obj = ois.readObject();
System.out.println(obj);
/*
Singer{name='周杰伦', age=18}
Singer{name='林俊杰', age=19}
Singer{name='潘玮柏', age=20}
*/
} catch (EOFException e) {
// 解决1: 如果读到EOFException, 结束循环
break;
}
}
}
}
class Singer implements Serializable {
//提供序列号: 不能修改变量名
//private static final long serialVersionUIDhahaha = 2L;
private static final long serialVersionUID = 2L;
private String name;
private int age;
public Singer() {
}
public Singer(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Singer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
24. Properties-概述
Properties继承自Hashtable, Hashtable实现了Map接口, 所以Properties本质是一个map集合
为什么IO这里讲Properties集合呢?
因为Properties中有两个和IO相关的方法, 非常好用
Properties的使用注意?
Properties创建时不写泛型, 可以存储任意类型的数据
但是一般我们都存字符串 (键值对定义为String类型)
25. Properties-作为map集合的基本使用
Properties作为map集合的基本使用练习
public class Demo {
public static void main(String[] args) {
Properties pro = new Properties();
// 增
pro.put("黄蓉", "郭靖");
pro.put("小龙女", "尹志平");
pro.put("赵敏", "张无忌");
pro.put("沈璧君", "萧十一郎");
pro.put("永琪", "尔康");
System.out.println(pro);
// 删
pro.remove("永琪");
System.out.println(pro);
// 改
pro.put("永琪", "小燕子");
System.out.println(pro);
// 查
// 遍历map1
Set<Object> keys = pro.keySet();
for (Object key : keys) {
Object value = pro.get(key);
System.out.println(key + "--" + value);
}
System.out.println("----------------");
// 遍历map2
Set<Map.Entry<Object, Object>> entries = pro.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
System.out.println(entry.getKey() + "--" + entry.getValue());
}
}
}
26. Properties-特有方法
Properties特有方法
1. Object setProperty(String key, String value); 设置集合的键和值,底层调HashTable的put
2. String getProperty(String key); 根据键返回值值
3. Set<String> stringPropertyNames(); 返回一个不可修改的键集, 键和值都是字符串
代码示例
public class Demo {
public static void main(String[] args) {
Properties pro = new Properties();
//1. Object setProperty(String key, String value); 设置集合的键和值,底层调HashTable的put
pro.setProperty("张三", "北京");
pro.setProperty("李四", "西安");
pro.setProperty("王五", "厦门");
System.out.println(pro); //{李四=西安, 张三=北京, 王五=厦门}
pro.setProperty("张三", "草滩六路");
System.out.println(pro); //{李四=西安, 张三=草滩六路, 王五=厦门}
//2. String getProperty(String key); 根据键返回值值
System.out.println(pro.get("张三")); //草滩六路
System.out.println(pro.get("李四")); //西安
System.out.println(pro.get("王五")); //厦门
//3. Set<String> stringPropertyNames(); 返回一个不可修改的键集, 键和值都是字符串
Set<String> keys = pro.stringPropertyNames();
for (String key : keys) {
Object value = pro.get(key);
System.out.println(key + "--" + value);
/*
李四--西安
张三--草滩六路
王五--厦门
*/
}
}
}
27. Properties-load
Properties和IO流结合的方法
1. void load(Reader reader); 从Properties文件读取键值对到内存中
2. void store(OutputStream out, String comments); 从内存写键值对数据到Properties文件
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//创建Properties对象
Properties pro = new Properties();
//创建输入流对象
FileReader fr = new FileReader("day12\\prop.properties");
//读数据到Properties集合
pro.load(fr);
//释放资源
fr.close();
//展示结果
System.out.println(pro); //{password=123, username=admin}
//加入多个键值对数据的结果
/*
{password=123, password2=12345, password1=1234, username2=admin2, username1=admin1, username=admin}
*/
}
}
28. Properties-store
代码示例
public class Demo {
public static void main(String[] args) throws IOException {
//创建Properties对象
Properties pro = new Properties();
//添加元素
pro.put("黄蓉", "郭靖");
pro.put("小龙女", "尹志平");
pro.put("赵敏", "张无忌");
pro.put("沈璧君", "萧十一郎");
pro.put("永琪", "尔康");
//创建输出流对象
FileWriter fw = new FileWriter("day12\\prop1.properties");
//写数据
pro.store(fw, "我是注释 aaa 111 哈哈哈");
//释放资源
fw.close();
}
}