day21
一、编码表
因为计算机中只能识别0和1, 要想在计算中表示中文,也就只能将中文或其它文字转为0和1,而转换的规则就是编码表。
1.1 ASCII编码表
注意:记住以下三个重要的数据即可
字符 十进制的数
0 48
A 65
a 97
1.2 GBK编码表
GBK编码表就是用来表示中文的,并且一个中文用两个字节表示。一个英文用一个字节表示(和ASCII编码表保持一致)
1.3 UTF-8编码表
UTF-8编码表可以用来表示中文,并且一个中文用三个字节表示。一个英文用一个字节表示(和ASCII编码表保持一致)
转换规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyz5uVXG-1620345078239)(img/UTF-8.jpg)]
1.4 注意事项
1. ANSI在Windows操作系统中表示GBK(也就是ANSI=GBK)
2. Unicode被称为统一码,是电脑科学领域的业界标准,它整理、编码了世界上大部分国家的文字,所以又被称为万国码。
3. UTF-8是Unicode标准的实现之一。(所以可以认为UTF-8=Unicode)
1.5 网站查询对照
中文和UTF-8对照:
https://unicode-table.com/en/#cjk-unified-ideographs
中文和GBK对照:
http://www.khngai.com/chinese/charmap/tblgbk.php?page=0
在线转换网站:
https://tool.chinaz.com/tools/unicode.aspx
1.6 总结 【掌握】
GBK 一个中文用两个字节表示。一个英文用一个字节表示
UTF-8 一个中文用三个字节表示。一个英文用一个字节表示
二、转换流
转换流就是为了正确的读取和写入字符。实际上就是一个字符流
2.1 InputStreamReader
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的
charset
的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
构造方法
InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader
InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader
常见方法
read() 一次读取一个字符
read(char[] ch) 一次读取一个字符数组
read(char[] ch, int offset, int len) 一次读取一个字符数组的一部分
package com.ujiuye.demo01_转换流;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) throws IOException {
//InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader
// InputStreamReader isr = new InputStreamReader(
// new FileInputStream("F:\\desktop\\Hello.txt"));
//InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader
InputStreamReader isr = new InputStreamReader(
new FileInputStream("F:\\desktop\\Hello.txt"), "gbk");
//read() 一次读取一个字符
int read = 0;
while((read = isr.read()) != -1){
System.out.println((char)read);
}
isr.close();
}
}
/*
注意:平台默认的字符集需要大家自行测试,我的经过测试默认为UTF-8编码
*/
2.2 OutputStreamWriter
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的
charset
码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造方法
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter
常见方法
write(int c) 一次写入一个字符
write(char[] ch) 一次写入一个字符数组
write(char[] ch, int offset, int len) 一次写入一个字符数组的一部分
write(String s) 一次写入一个字符串
write(String s, int offset, int len) 一次写入一个字符串的一部分
package com.ujiuye.demo01_转换流;
import java.io.*;
public class Demo2 {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day21\\b.txt"));
//OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day21\\c.txt"), "gbk");
//write(String s) 一次写入一个字符串
osw.write("Hello中国");
osw.close();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IG1meQew-1620345078241)(img/image-20210506105447890-1620270011517.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V706FKtE-1620345078242)(img/image-20210506105956715.png)]
三、标准输入输出流(了解)
3.1 标准输入流
System.in
本质:InputStream 字节流
作用:默认关联到键盘,可以通过键盘录入数据
如何更换输入流的源头:使用System类中的setIn方法重新分配“标准”输入流
static void setIn(InputStream in) 重新分配“标准”输入流
package com.ujiuye.demo02_标准输入输出流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
//之前的
// Scanner sc = new Scanner(System.in);
// int i = sc.nextInt();
// System.out.println(i);
//更换之后的:可以直接从指定文件Hello.txt中读取内容
System.setIn(new FileInputStream("F:\\desktop\\Hello.txt"));
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(s);
}
}
3.2 标准输出流
System.out
本质:PrintStream 字节流
作用:默认关联到控制台,可以直接在控制上打印
如何更换输出流的源头:使用System类中的setOut方法重新分配“标准”输出流
static void setOut(PrintStream out) 重新分配“标准”输出流
package com.ujiuye.demo02_标准输入输出流;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class Demo2 {
public static void main(String[] args) throws FileNotFoundException {
//之前的
// PrintStream out = System.out;
// out.println("Hello中国");
//分配之后的:直接将内容写入到指定文件d.txt中
System.setOut(new PrintStream(new File("day21\\d.txt")));
System.out.println("你好World");
}
}
四、对象序列化
4.1 概念
对象流:就是用来将对象存储到文件中,或者将文件中的对象获取出来的流。
序列化: 用对象流将对象存储到文件中
反序列化: 用对象流将文件中的对象获取出来
对象:所有Object的子类new出来的内容都是对象
4.2 作用
1. 持久化的存储数据(也就是存储到电脑上的某一个文件中)
2. 可以在网络上传输数据(也就是对象)
4.3 对象输出流 ObjectOutputStream
用来序列化
构造方法
ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream
常见方法
void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream
注意事项
1. writeObject中只能接收实现了Serializable接口的对象。
Serializable接口就是一个序列化的标志,没有这个标志就不能进行序列化
就相当于去市场上卖猪肉,猪肉上必须要有一个戳,有这个戳就证明这个猪肉是安全的
2. 将对象序列化到文件后,直接打开文件是读不懂文件内容,必须要通过反序列化才能准确的读懂文件中的对象。
package com.ujiuye.demo03_序列化.普通版本;
import java.io.Serializable;
public class Person implements Serializable {
String name;
int age;
public Person() {
}
public Person(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;
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Demo {
public static void main(String[] args) throws IOException {
//ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day21\\person.txt"));
//void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream
Person p = new Person("Robin", 18);
Person p2 = new Person("Ted", 25);
Person p3 = new Person("Neo", 29);
oos.writeObject(p);
oos.writeObject(p2);
oos.writeObject(p3);
oos.close();
}
}
4.4 对象输入流 ObjectInputStream
用来反序列化
构造方法
ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream
常见方法
Object readObject() 从 ObjectInputStream 读取对象
注意事项
1. 抛出了EOFException异常(End Of File异常)就是已经到达了文件的末尾
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QuErDUBB-1620345078244)(img/image-20210506141907300.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5LPLJYU-1620345078245)(img/image-20210506141927786.png)]
package com.ujiuye.demo03_序列化.普通版本;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Demo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的 ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day21\\person.txt"));
//Object readObject() 从 ObjectInputStream 读取对象
Object o = ois.readObject();
System.out.println(o);
Object o2 = ois.readObject();
System.out.println(o2);
Object o3 = ois.readObject();
System.out.println(o3);
}
}
/*
输出结果:
Person{name='Robin', age=18}
Person{name='Ted', age=25}
Person{name='Neo', age=29}
*/
4.5 使用集合改进序列化和反序列化 【掌握】
出现问题的原因: 不知道被序列化了多少个对象,所以反序列化的时候出现异常
如何解决:
1. 将所有的对象先存储到集合中
2. 将集合序列化(此集合包含了很多个对象)
3. 将集合反序列化
4. 遍历集合即可
package com.ujiuye.demo03_序列化.优化版本;
import java.io.Serializable;
public class Person implements Serializable {
String name;
int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day21\\pp.txt"));
Person p = new Person("robin", 18);
Person p2 = new Person("ted", 23);
Person p3 = new Person("neo", 29);
// 1. 将所有的对象先存储到集合中
ArrayList<Person> al = new ArrayList<>();
al.add(p);
al.add(p2);
al.add(p3);
//2. 将集合序列化(此集合包含了很多个对象)
oos.writeObject(al);
oos.close();
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
public class Demo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day21\\pp.txt"));
//此反序列化取出来的是一个集合对象(集合对象中包含了很多Person对象)
ArrayList<Person> list = (ArrayList<Person>) ois.readObject();
//遍历ArrayList集合,获取到真正的Person对象
for (Person person : list) {
System.out.println(person);
}
ois.close();
}
}
/*
输出结果:
Person{name='robin', age=18}
Person{name='ted', age=23}
Person{name='neo', age=29}
*/
4.6 版本号serialVersionUID和关键字transient
版本号serialVersionUID
1. 编译一个类生成一个class文件的时候,它会生成long类型的版本号
2. 改动一个类也会生成一个class文件,它会生成新的一个long类型的版本号
注意:以上两个版本号是不一致的。
出现问题的原因就是:
1. 我们在序列化的时候,会根据class文件的版本号进行序列化
2. 我们反序列化的时候,会根据class文件的版本号进行对比,如果一致,那么正常进行反序列化;如果不一致,那么报出InvalidClassException异常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t9p4Li1X-1620345078245)(img/image-20210506152258771.png)]
如何解决这个问题:
只要保证class文件的版本号一致即可。所以我们可以直接在类中将这个版本号给固定好即可(以后无论再修改多少次这个版本号始终是固定的,不变的)
public static final long serialVersionUID = 1L;
关键字transient
如果某些属性我们不想序列化怎么办?
官方提供了一个关键字transient修饰不想序列化的属性即可。
public class Person implements Serializable {
//保证了版本号的一致性,以后再修改这个Person类,版本号也始终都是1
public static final long serialVersionUID = 1L;
String name;
//不想被序列化的属性可以通过transient修饰
transient int age;
}
五、Properties
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。注意:实际上Properties类就是Map的子类
5.1 作用
主要用来读取和修改配置文件的。这个配置文件一般都是properties为扩展名的。
注意:
1. 此文件的后缀为properties
2. 此文件中的注释为:# 注释的内容
3. 此文件中都是存储的成对的文件: 属性=属性值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4NbJjo1M-1620345078246)(img/image-20210506160724178.png)]
5.2 构造方法
Properties() 创建一个无默认值的空属性列表
5.3 常见方法
因为Properties类是Hashtable的子类,而Hashtable是Map的实现类,所以Properties类可以使用Map所有的方法
public V put(K key, V value)
Object setProperty(String key, String value) 调用 Hashtable 的方法 put。 如果再存入一个同样的key值, 那么value会替换为新的value,而将此key对应的原来的value值给替换掉(和Map是一模一样的)
String getProperty(String key) 用指定的键在此属性列表中搜索属性
Set<String> stringPropertyNames() 获取此Properties中所有属性的Set集合
package com.ujiuye.demo04_Properties;
import java.util.Properties;
import java.util.Set;
public class Demo {
public static void main(String[] args) {
//Properties() 创建一个无默认值的空属性列表
Properties prop = new Properties();
//public V put(K key, V value)
// prop.put("Hello", "Jerry");
//Object setProperty(String key, String value) 调用 Hashtable 的方法 put
prop.setProperty("001", "robin");
prop.setProperty("002", "ted");
prop.setProperty("001", "Jerry");
// System.out.println(prop); //{002=ted, 001=Jerry}
//String getProperty(String key) 用指定的键在此属性列表中搜索属性
// System.out.println(prop.getProperty("002")); //ted
// System.out.println(prop.getProperty("001")); //Jerry
//Set<String> stringPropertyNames()
Set<String> strings = prop.stringPropertyNames();
for (String string : strings) {
System.out.println(string + "---" + prop.getProperty(string));
}
}
}
5.4 Properties和IO结合使用读取配置文件 【重点、掌握】
常见方法
void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)
void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
void store(OutputStream out, String comments) 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流
void store(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符
操作步骤
1. 先建立一个properties文件
2. 在properties文件中写上一些键值对:一般都会存储一些常见的用户名、密码等
如:
属性=属性值
username=robin
password=123456
注意:
1. 里面都是使用英文的
2. 属性和属性值中间用=分隔
3. 需要注释的话,必须写为: #注释的内容
(一般来说:配置文件别人都会给我们提供好,我们直接复制到项目中即可)
3. 通过load方法将properties文件读取到Properties中
4. 可以遍历获取Propertie中的内容,也可以通过setProperty方法设置配置文件中的内容,并通过store方法保存修改后的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cHcUBZDz-1620345078247)(img/image-20210506165400863.png)]
package com.ujiuye.demo04_Properties;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Demo2 {
public static void main(String[] args) throws IOException {
//1. 创建Properties对象
Properties prop = new Properties();
//2. 通过Properties对象调用load方法来将文件中的内容加载到Properties中
prop.load(new FileReader("day21\\config.properties"));
//3. 遍历获取Propertie中的内容
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key + "---" + prop.getProperty(key));
}
System.out.println("-------------------------------");
//3. 通过setProperty方法设置配置文件中的内容,并通过store方法保存修改后的内容
prop.setProperty("password", "666666");
prop.store(new FileWriter("day21\\config.properties"), "change user's password 16:41:02");
}
}
/*
输出结果:
password---123456
username---robin
*/
六、IO流总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7LJseaRT-1620345078248)(img/image-20210506171822974.png)]
过Properties对象调用load方法来将文件中的内容加载到Properties中
prop.load(new FileReader(“day21\config.properties”));
//3. 遍历获取Propertie中的内容
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
System.out.println(key + "---" + prop.getProperty(key));
}
System.out.println("-------------------------------");
//3. 通过setProperty方法设置配置文件中的内容,并通过store方法保存修改后的内容
prop.setProperty("password", "666666");
prop.store(new FileWriter("day21\\config.properties"), "change user's password 16:41:02");
}
}
/*
输出结果:
password—123456
username—robin
*/
### 六、IO流总结
[外链图片转存中...(img-7LJseaRT-1620345078248)]