Java进阶: 编码和解码.字符流常用方法?字符流注意事项?字符输入流读取数据注意事项?字符缓冲流特有方法?什么是转换流?如何在读取文件时候指定字符集?对象操作流注意事项?Properties集合特有方法
重难点梳理
知识点梳理
超详细讲义
-
字符流
-
字符缓冲流
-
-
序列化流
-
Properties集合
1.字符流
1.1 字节流操作出现中文乱码的问题 【了解】
package com.itheima.charstream1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class CharStreamDemo1 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("charstream\\a.txt");
int b ;
while((b = fis.read()) != -1){
System.out.println((char)b);
}
fis.close();
}
}
1.2 字符流-编码表【了解】
1.常见的字符集(码表)
2.常见的编码/解码方式
ASCII编码: ASCII字符集(码表)的编码方式,1个字节,最多能表示256个字符,适用于英文
GBK编码:GBK字符集(码表)的编码式,用1个字节表示英文,用2个字节表示中文
UTF-8编码:Unicode字符集(码表)的编码方式,用1个字节表示英文,用3个字节表示中文
3.中文存储和展示过程
4.记忆
windows平台默认编码方式是GBK,而ideal和工作中用的编码方式是UTF-8
1.3 字符串-编码和解码【重点】
1.编码方法
方法 | 说明 |
---|---|
public byte[] getBytes() | 使用平台的默认字符集将该String 编码为一系列字节,将结果存储到新的字节数组中 |
public byte[] getBytes(String charsetName) | 使用命名的字符集将这个String 编码成一个字节序列,将结果存储到一个新的字节数组中 |
2.解码方法
方法 | 说明 |
---|---|
String(byte[] bytes) |
通过使用平台的默认字符集解码指定的字节数组来构造新的 String |
String(byte[] bytes, String charsetName) |
构造一个新的String 由指定用指定的字节的数组解码 |
示例代码
package com.itheima.charstream1;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class CharStreamDemo2 {
public static void main(String[] args) throws UnsupportedEncodingException {
//method1();
// String•(byte[] bytes):
//通过使用平台的默认字符集解码指定的字节数组来构造新的 String
// String•(byte[] bytes, String charsetName):
//通过指定的字符集解码指定的字节数组来构造新的 String
//UTF-8
byte [] bytes1 = {-23, -69, -111, -23, -87, -84, -25, -88, -117, -27, -70, -113, -27, -111, -104};
//gbk
byte [] bytes2 = {-70, -38, -62, -19, -77, -52, -48, -14, -44, -79};
//利用默认的UTF-8进行解码
String s1 = new String(bytes1);
System.out.println(s1);//黑马程序员
//利用指定的GBK进行解码
String s2 = new String(bytes2,"gbk");
System.out.println(s2);//黑马程序员
}
private static void method1() throws UnsupportedEncodingException {
// byte[] getBytes•():
//使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
// byte[] getBytes•(String charsetName):
//使用指定的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
String s = "黑马程序员";
//利用idea默认的UTF-8将中文编码为一系列的字节
byte[] bytes1 = s.getBytes();
System.out.println(Arrays.toString(bytes1));
//byte[] bytes2 = s.getBytes("UTF-8");
byte[] bytes2 = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
}
}
1.4 字节流读取中文出现乱码的原因【了解】
在Ideal中默认编码是UTF-8,中文用三个字节表示,而用字节流读出中文时,如果一次只读取一个字节就强转,就造成了乱码
1.5 字符流-读取中文的过程 【了解】
1.字节流和字符流的使用总结
1.想要进行拷贝,一律使用字节流或字节缓冲流
2.如果是对纯文本文件的读取,使用字符流
1.6字符流写数据【重点】
(共4点)
1.字符输出流介绍
Writer: 用于写入字符流的抽象父类
FileWriter: 用于写入字符流的常用子类
2.构造方法
方法名 | 说明 |
---|---|
FileWriter(File file) | 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter(File file, boolean append) | 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter(String fileName) | 根据给定的文件名构造一个 FileWriter 对象 |
FileWriter(String fileName, boolean append) | 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 |
3.成员方法
方法名 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
4.字符流写数据的步骤
package com.itheima.charstream1;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
//创建字符输出流的对象
//FileWriter fw = new FileWriter(new File("charstream\\a.txt"));
FileWriter fw = new FileWriter("charstream\\a.txt");
/*//写出数据
//void write•(int c) 写一个字符
fw.write(97);
fw.write(98);
fw.write(99);*/
//void write•(char[] cbuf) 写出一个字符数组
/* char [] chars = {97,98,99,100,101};
fw.write(chars);*/
//void write•(char[] cbuf, int off, int len) 写出字符数组的一部分
/*char [] chars = {97,98,99,100,101};
fw.write(chars,0,3);*/
//void write•(String str) 写一个字符串
/* String line = "黑马程序员abc";
fw.write(line);*/
//void write•(String str, int off, int len) 写一个字符串的一部分
String line = "黑马程序员abc";
fw.write(line,0,2);
//释放资源
fw.close();
}
}
1.7 字符流写数据注意事项【了解】
package com.itheima.charstream1;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo4 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("charstream\\a.txt");
//fw.write("黑马程序员");
//fw.write(97);
fw.write("97");
fw.close();
}
}
1.8 字符流-flush和close()方法 【重点】
刷新和关闭的方法
方法名 | 说明 |
---|---|
flush() | 刷新流,之后还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先写出数据。一旦关闭,就不能再写数据 |
代码演示
package com.itheima.charstream1;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo5 {
public static void main(String[] args) throws IOException {
//flush()刷新流。刷新完毕之后,还可以继续写数据
//close()关闭流。释放资源。一旦关闭,就不能写数据
FileWriter fw = new FileWriter("charstream\\a.txt");
fw.write("黑马程序员");
//fw.flush();
fw.write("666");
//fw.flush();
fw.close();
fw.write("aaa");//Stream closed
}
}
1.9字符流读数据【重点】
1.字符输入流介绍
Reader: 用于读取字符流的抽象父类
FileReader: 用于读取字符流的常用子类
2.构造方法
方法名 | 说明 |
---|---|
FileReader(File file) | 在给定从中读取数据的 File 的情况下创建一个新 FileReader |
FileReader(String fileName) | 在给定从中读取数据的文件名的情况下创建一个新 FileReader |
3.成员方法
方法名 | 说明 |
---|---|
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
4.字符流读数据的步骤
1.创建字符输入流对象
2.调用读数据方法
3.释放资源
5.字符流读数据注意事项
-
创建对象
文件必须存在
-
释放资源
必须关闭流
代码演示
package com.itheima.charstream1;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo6 {
public static void main(String[] args) throws IOException {
//创建字符输入流的对象
// FileReader fr = new FileReader(new File("charstream\\a.txt"));
FileReader fr = new FileReader("charstream\\a.txt");
//读取数据
//一次读取一个字符
int ch;
while((ch = fr.read()) != -1){
System.out.println((char) ch);
}
//释放资源
fr.close();
}
}
package com.itheima.charstream1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo7 {
public static void main(String[] args) throws IOException {
//一次读取多个字符。
//创建对象
FileReader fr = new FileReader("charstream\\a.txt");
//创建一个数组
char [] chars = new char[1024];
int len;
//read方法还是读取,但是是一次读取多个字符
//他把读到的字符都存入到chars数组。
//返回值:表示本次读到了多少个字符。
while((len = fr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
fr.close();
}
}
1.10字符流用户注册案例【重点】
-
案例需求
将键盘录入的用户名和密码保存到本地实现永久化存储
要求用户名独占一行,密码独占一行
-
实现步骤
-
获取用户输入的用户名和密码
-
将用户输入的用户名和密码写入到本地文件中
-
关流,释放资源
-
-
代码实现
package com.itheima.charstream1;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
public class CharStreamDemo8 {
public static void main(String[] args) throws IOException {
//将键盘录入的用户名和密码保存到本地实现永久化存储
//要求:用户名独占一行,密码独占一行
//分析:
//1,实现键盘录入,把用户名和密码录入进来
Scanner sc = new Scanner(System.in);
System.out.println("请录入用户名");
String username = sc.next();
System.out.println("请录入密码");
String password = sc.next();
//2.分别把用户名和密码写到本地文件。
FileWriter fw = new FileWriter("charstream\\a.txt");
//将用户名和密码写到文件中
fw.write(username);
//表示写出一个回车换行符 windows \r\n MacOS \r Linux \n
fw.write("\r\n");
fw.write(password);
//刷新流
fw.flush();
//释放资源
fw.close();
}
}
1.11字符缓冲输入流-读取数据【重点】
1.字符缓冲流介绍
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取
2.构造方法
方法名 | 说明 |
---|---|
BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
代码演示
package com.itheima.charstream1;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo9 {
public static void main(String[] args) throws IOException {
//字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("charstream\\a.txt"));
//读取数据
char [] chars = new char[1024];
int len;
while((len = br.read(chars)) != -1){
System.out.println(new String(chars,0,len));
}
br.close();
}
}
1.12 字符缓冲输出流 【重点】
1.字符缓冲输出流介绍:
BufferedWriter: 将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入
2.构造方法
方法名 | 说明 |
---|---|
BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
3.常用方法
方法名 | 说明 |
---|---|
public void write(int c) | 写一个字符 |
public void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
public void write(String s, int off, int len) | 写一个字符串的一部分 |
public void flush() | 刷新流 |
package com.itheima.charstream1;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo10 {
public static void main(String[] args) throws IOException {
//字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\a.txt"));
//写出数据
//实际写出的是97对应的字符a
bw.write(97);
bw.write("\r\n");
//实际写出的是97 - 101 对应的字符 abcde
char [] chars = {97,98,99,100,101};
bw.write(chars);
bw.write("\r\n");
//实际写的是abc
bw.write(chars,0,3);
bw.write("\r\n");
//会把字符串的内容原样写出
bw.write("黑马程序员");
bw.write("\r\n");
//会把字符串的一部分写出 abcde
String line = "abcdefg";
bw.write(line,0,5);
bw.flush();
bw.close();
}
}
1.13字符缓冲流特有功能【重点】
1.方法介绍
BufferedWriter:
方法名 | 说明 |
---|---|
void newLine() | 写一行行分隔符,行分隔符字符串由系统属性定义 |
BufferedReader:
方法名 | 说明 |
---|---|
String readLine() | 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null |
代码演示
package com.itheima.charstream1;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo11 {
public static void main(String[] args) throws IOException {
//字符缓冲流的特有功能
//字符缓冲输出流BufferedWrite : newLine 跨平台的换行符
//创建对象
BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\a.txt"));
//写出数据
bw.write("黑马程序员666");
//跨平台的回车换行
bw.newLine();
bw.write("abcdef");
//跨平台的回车换行
bw.newLine();
bw.write("-------------");
//刷新流
bw.flush();
//释放资源
bw.close();
}
}
package com.itheima.charstream1;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo12 {
public static void main(String[] args) throws IOException {
//字符缓冲流的特有功能
//字符缓冲输入流BufferedReader: readLine 读一整行
//创建对象
BufferedReader br = new BufferedReader(new FileReader("charstream\\a.txt"));
//读取数据
String line1 = br.readLine();
String line2 = br.readLine();
String line3 = br.readLine();
//在之前,如果读不到数据,返回-1
//但是readLine如果读不到数据返回null
String line4 = br.readLine();
String line5 = br.readLine();
System.out.println(line1);
System.out.println(line2);
System.out.println(line3);
System.out.println(line4);
System.out.println(line5);
// 释放资源
br.close();
}
}
package com.itheima.charstream1;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo13 {
public static void main(String[] args) throws IOException {
//字符缓冲流的特有功能
//字符缓冲输入流BufferedReader: readLine 读一整行
//创建对象
BufferedReader br = new BufferedReader(new FileReader("charstream\\a.txt"));
//使用循环来进行改进
String line;
//可以读取一整行数据。一直读,读到回车换行为止。
//但是他不会读取回车换行符。
while((line = br.readLine()) != null){
System.out.println(line);
}
//释放资源
br.close();
}
}
1.14字符缓冲流操作文件中数据排序案例【重点】
-
案例需求
使用字符缓冲流读取文件中的数据,排序后再次写到本地文件
-
实现步骤
-
将文件中的数据读取到程序中
-
对读取到的数据进行处理
-
将处理后的数据添加到集合中
-
对集合中的数据进行排序
-
将排序后的集合中的数据写入到文件中
-
-
代码实现
package com.itheima.charstream1;
import java.io.*;
import java.util.Arrays;
public class CharStreamDemo14 {
public static void main(String[] args) throws IOException {
//需求:读取文件中的数据,排序后再次写到本地文件
//分析:
//1.要把文件中的数据读取进来。
BufferedReader br = new BufferedReader(new FileReader("charstream\\sort.txt"));
//输出流一定不能写在这里,因为会清空文件中的内容
//BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\sort.txt"));
String line = br.readLine();
System.out.println("读取到的数据为" + line);
br.close();
//2.按照空格进行切换
String[] split = line.split(" ");//9 1 2 5 3 10 4 6 7 8
//3.把字符串类型的数组变成int类型
int [] arr = new int[split.length];
//遍历split数组,可以进行类型转换。
for (int i = 0; i < split.length; i++) {
String smallStr = split[i];
//类型转换
int number = Integer.parseInt(smallStr);
//把转换后的结果存入到arr中
arr[i] = number;
}
//4.排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
//5.把排序之后结果写回到本地 1 2 3 4...
BufferedWriter bw = new BufferedWriter(new FileWriter("charstream\\sort.txt"));
//写出
for (int i = 0; i < arr.length; i++) {
bw.write(arr[i] + " ");
bw.flush();
}
//释放资源
bw.close();
}
}
1.15 IO流小结【了解】
-
IO流小结
2.转换流
2.1转换流概念【了解】
(共2点)
1.什么是转换流?
-
InputStreamReader:是从字节流到字符流的桥梁,父类是Reader
它读取字节,并使用指定的编码将其解码为字符
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
-
OutputStreamWriter:是从字符流到字节流的桥梁,父类是Writer
是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
2.2转换流指定编码读写数据【了解】
(共4点)
1.为什么会乱码?
private static void method1() throws IOException {
FileReader fr = new FileReader("C:\\Users\\apple\\Desktop\\a.txt");
int ch;
while ((ch = fr.read())!=-1){
System.out.println((char) ch);
}
fr.close();
}
读写的编码不一致
2.如何解决呢?
1.在jdk11之前,使用转换流
2.在jdk11之后,可以直接使用FileReader
3.使用转换流解决
1.构造方法
方法名 | 说明 |
---|---|
InputStreamReader(InputStream in) | 使用默认字符编码创建InputStreamReader对象 |
InputStreamReader(InputStream in,String chatset) | 使用指定的字符编码创建InputStreamReader对象 |
OutputStreamWriter(OutputStream out) | 使用默认字符编码创建OutputStreamWriter对象 |
OutputStreamWriter(OutputStream out,String charset) | 使用指定的字符编码创建OutputStreamWriter对象 |
代码演示
private static void method2() throws IOException {
//如何解决乱码现象
//文件是什么码表,那么咱们就必须使用什么码表去读取.
//我们就要指定使用GBK码表去读取文件.
InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\apple\\Desktop\\a.txt"),"gbk");
int ch;
while((ch = isr.read())!=-1){
System.out.println((char) ch);
}
isr.close();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\apple\\Desktop\\b.txt"),"UTF-8");
osw.write("我爱学习,谁也别打扰我");
osw.close();
}
4.在jkd11之后,使用FileReader
public static void main(String[] args) throws IOException { //method1(); //method2(); //在JDK11之后,字符流新推出了一个构造,也可以指定编码表 FileReader fr = new FileReader("C:\\Users\\apple\\Desktop\\a.txt", Charset.forName("gbk")); int ch; while ((ch = fr.read())!=-1){ System.out.println((char) ch); } fr.close(); }
3.对象操作流
3.1 对象流的基本特点 【了解】
1.对象流的基本特点?
对象操作流可以将对象以字节的形式写到本地文件中,需要时可以再次用对象操作流读到内存中,直接变成对象
2.为什么要使用对象流?
对象的信息保存到磁盘中,如果使用前面所学的知识来实现,会非常的繁琐。使用对象流就非常的方便
3.2对象操作流-序列化【了解】
(共4点)
1.什么是序列化?
序列化就是将对象转换为字节流,以便存储到特点存储介质(例如磁盘)的过程
2.什么是反序列化?
反序列化就是将字节流,转换为对象的过程
3.对象操作流介绍
-
对象操作输出流(对象序列化流):ObjectOutputStream
就是将对象保存到磁盘中,或者在网络中传输对象
-
对象操作输入流(对象反序列化流): ObjectInputStream
把写到本地文件中的对象读到内存中,或者接收网络中传输的对象
4.如何使用对象输出流(对象序化流)
(共3点)
1.构造方法
方法名 | 说明 |
---|---|
ObjectOutputStream(OutputStream out) | 创建一个写入指定的OutputStream的ObjectOutputStream |
2.序列化对象的方法
方法名 | 说明 |
---|---|
void writeObject(Object obj) | 将指定的对象写入ObjectOutputStream |
示例代码
学生类
package com.itheima.convertedio; import java.io.Serializable; //如果想要这个类的对象能被序列化,那么这个类必须要实现一个接口.Serializable //Serializable 接口的意义 //称之为是一个标记性接口,里面没有任何的抽象方法 //只要一个类实现了这个Serializable接口,那么就表示这个类的对象可以被序列化. public class User implements Serializable { . private String username; private transient String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
测试类
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ConvertedDemo3 { public static void main(String[] args) throws IOException { User user = new User("zhangsan","qwer"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); oos.writeObject(user); oos.close(); } }
3.注意事项
-
一个对象要想被序列化,该对象所属的类必须必须实现Serializable 接口
-
Serializable是一个标记接口,实现该接口,不需要重写任何方法
package cn.itheima.domain; import java.io.Serializable; public class Student implements Serializable { private String name; public String password; public Student() { } public Student(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package cn.itheima; import cn.itheima.domain.Student; import java.io.*; public class TestTransient { public static void main(String[] args) throws IOException, ClassNotFoundException { //writeStudent(); readStudent(); } public static void writeStudent() throws IOException { ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("1.txt")); Student.password="123"; Student student = new Student("aaa"); oos.writeObject(student); } }
3.2对象反序列化流-反序化【了解】
(共2点)
1.回顾什么是对象操作输入流?
对象反序列化流: ObjectInputStream
ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
2.如何使用?
1.构造方法
方法名 | 说明 |
---|---|
ObjectInputStream(InputStream in) | 创建从指定的InputStream读取的ObjectInputStream |
2.反序列化对象的方法
方法名 | 说明 |
---|---|
Object readObject() | 从ObjectInputStream读取一个对象 |
示例代码
package com.itheima.convertedio; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ConvertedDemo4 { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); User o = (User) ois.readObject(); System.out.println(o); ois.close(); } }
3.3对象操作流-两个注意点(serialVersionUID&transient)【了解】
1.serialVersionUID
-
用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
-
会出问题,会抛出InvalidClassException异常
-
-
如果出问题了,如何解决呢?
-
重新序列化
-
给对象所属的类加一个serialVersionUID
-
private static final long serialVersionUID = 42L;
-
-
2.transient[ˈtrænziənt]
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
-
给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
示例代码
学生类
package com.itheima.convertedio; import java.io.Serializable; //如果想要这个类的对象能被序列化,那么这个类必须要实现一个接口.Serializable //Serializable 接口的意义 //称之为是一个标记性接口,里面没有任何的抽象方法 //只要一个类实现了这个Serializable接口,那么就表示这个类的对象可以被序列化. public class User implements Serializable { //serialVersionUID 序列号 //如果我们自己没有定义,那么虚拟机会根据类中的信息会自动的计算出一个序列号. //问题:如果我们修改了类中的信息.那么虚拟机会再次计算出一个序列号. //第一步:把User对象序列化到本地. --- -5824992206458892149 //第二步:修改了javabean类. 导致 --- 类中的序列号 4900133124572371851 //第三步:把文件中的对象读到内存. 本地中的序列号和类中的序列号不一致了. //解决? //不让虚拟机帮我们自动计算,我们自己手动给出.而且这个值不要变. private static final long serialVersionUID = 1L; private String username; private transient String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
测试类
package com.itheima.convertedio; import java.io.*; import java.util.ArrayList; public class ConvertedDemo5 { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.写对象 //2.修改javabean类 //3.读对象 //写对象 --- 序列化 //method1(); //读对象 --- 反序列化 method2(); } private static void method2() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); User o = (User) ois.readObject(); System.out.println(o); ois.close(); } private static void method1() throws IOException { User user = new User("zhangsan","qwer"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); oos.writeObject(user); oos.close(); } }
3.4对象操作流练习【了解】
-
案例需求
创建多个学生类对象写到文件中,再次读取到内存中
-
实现步骤
-
创建序列化流对象
-
创建多个学生对象
-
将学生对象添加到集合中
-
将集合对象序列化到文件中
-
创建反序列化流对象
-
将文件中的对象数据,读取到内存中
-
-
代码实现
学生类
package com.itheima.convertedio; import java.io.Serializable; public class Student implements Serializable { private static final long serialVersionUID = 2L; private String name; private int age; public Student() { } public Student(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 "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
测试类(6,7)
package com.itheima.convertedio; import java.io.*; public class ConvertedDemo6 { public static void main(String[] args) throws IOException, ClassNotFoundException { Student s1 = new Student("杜子腾",16); Student s2 = new Student("张三",23); Student s3 = new Student("李四",24); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); oos.writeObject(s1); oos.writeObject(s2); oos.writeObject(s3); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); Object obj; /* while((obj = ois.readObject()) != null){ System.out.println(obj); }*/ while(true){ try { Object o = ois.readObject(); System.out.println(o); } catch (EOFException e) { break; } } ois.close(); } }
package com.itheima.convertedio; import java.io.*; import java.util.ArrayList; public class ConvertedDemo7 { public static void main(String[] args) throws IOException, ClassNotFoundException { Student s1 = new Student("杜子腾",16); Student s2 = new Student("张三",23); Student s3 = new Student("李四",24); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); ArrayList<Student> list = new ArrayList<>(); list.add(s1); list.add(s2); list.add(s3); //我们往本地文件中写的就是一个集合 oos.writeObject(list); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); ArrayList<Student> list2 = (ArrayList<Student>) ois.readObject(); for (Student student : list2) { System.out.println(student); } ois.close(); } }
4.Properties集合
4.1 Properties -概述【了解】
1.Properties介绍
-
是一个Map体系的集合类
-
只存字符串
4.2Properties作为Map集合的使用【重点】
Properties基本使用
package com.itheima.propertiesio; import java.util.Map; import java.util.Properties; import java.util.Set; public class PropertiesDemo1 { public static void main(String[] args) { Properties prop = new Properties(); //增 prop.put("小龙女","尹志平"); prop.put("郭襄","杨过"); prop.put("黄蓉","欧阳克"); System.out.println(prop); //删 //prop.remove("郭襄"); //System.out.println(prop); //改 //put --- 如果键不存在,那么就添加,如果键存在,那么就覆盖. prop.put("小龙女","杨过"); System.out.println(prop); //查 //Object value = prop.get("黄蓉"); //System.out.println(value); //遍历 Set<Object> keys = prop.keySet(); for (Object key : keys) { Object value = prop.get(key); System.out.println(key + "=" + value); } System.out.println("========================"); //装的是所有的键值对对象. Set<Map.Entry<Object, Object>> entries = prop.entrySet(); for (Map.Entry<Object, Object> entry : entries) { Object key = entry.getKey(); Object value = entry.getValue(); System.out.println(key + "=" + value); } } }
4.2Properties作为Map集合的特有方法【重点】
1.特有方法
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是String类型,底层调用 Hashtable方法 put |
String getProperty(String key) | 使用此属性列表中指定的键搜索属性 |
Set<String> stringPropertyNames() | 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
示例代码
package com.itheima.propertiesio; import java.util.Properties; import java.util.Set; public class PropertiesDemo2 { public static void main(String[] args) { //Object setProperty(String key, String value) --- put //设置集合的键和值,都是String类型,底层调用 Hashtable方法 put Properties prop = new Properties(); prop.setProperty("江苏","南京"); prop.setProperty("安徽","南京"); prop.setProperty("山东","济南"); System.out.println(prop); //String getProperty(String key) --- get //使用此属性列表中指定的键搜索属性 /* String value = prop.getProperty("江苏"); System.out.println(value);*/ //Set<String> stringPropertyNames() --- keySet //从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 Set<String> keys = prop.stringPropertyNames(); for (String key : keys) { String value = prop.getProperty(key); System.out.println(key + "=" + value); } } }
4.3Properties-load【重点】
-
和IO流结合的方法
方法名 说明 void load(Reader reader) 将字符输入流中的数据加载到Properties对象中 -
示例代码
package com.itheima.propertiesio; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Properties;
public class PropertiesDemo3 { public static void main(String[] args) throws IOException { //void load(Reader reader) 将本地文件中的键值对数据读取到集合中 //void store(Writer writer, String comments) 将集合中的数据以键值对形式保存在本地
//读取 Properties prop = new Properties(); FileReader fr = new FileReader("prop.properties"); //调用完了load方法之后,文件中的键值对数据已经在集合中了. prop.load(fr); fr.close(); System.out.println(prop); }
}
4.4Properties-store【重点】
和IO流结合的方法
方法名 | 说明 |
---|---|
void store(Writer writer, String comments) | 将Properties集合中的数据存入字符输出流 |
示例代码
package com.itheima.propertiesio; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; public class PropertiesDemo4 { public static void main(String[] args) throws IOException { //void load(Reader reader) 将本地文件中的键值对数据读取到集合中 //void store(Writer writer, String comments) 将集合中的数据以键值对形式保存在本地 Properties prop = new Properties(); prop.put("zhangsan","123"); prop.put("lisi","456"); prop.put("wangwu","789"); FileWriter fw = new FileWriter("prop.properties"); prop.store(fw,null); fw.close(); } }
小结
1.什么是Properties?
2.Properties的基本使用?
3.Properties与IO流结合的用法?
课后扩展
题目1[字符流]
请使用“便捷字符流”配合数组将文件"窗里窗外"的内容打印到控制台,并统计出读文本共使用的时间;
效果:
参考代码:
public static void main(String[] args) throws IOException {
long t1 = System.currentTimeMillis();
FileReader fr = new FileReader("窗里窗外.txt",Charset.forName("gbk"));
char[] arr = new char[1024];
int len = 0;
while ((len=fr.read(arr))!=-1){
String s = new String(arr, 0, len);
System.out.print(s);//注意输出语句不带 ln
}
fr.close();
long t2 = System.currentTimeMillis();
System.out.println();
System.out.println("-----------------------------------------------");
System.out.println("读取文件共使用了:"+(t2-t1)+"毫秒!");
}
题目2[字符流缓冲流]
将下列文件中的学生信息按照年龄升序排序后重新写回原文件;
要求:
1:使用字符缓冲流完成;
2:每次循环读取一行信息
3:写数据的时候换行使用newLine方法;
效果:
1.txt文件排序前:
1.txt文件排序后:
参考代码:
public static void main(String[] args) throws Exception {
//创建文件对象和字符缓冲流对象,准备读数据
File f = new File("1.txt");
BufferedReader br = new BufferedReader(new FileReader(f));
//准备TreeSet集合,用于保存读到的学生对象并排序
TreeSet<Student> set = new TreeSet<>((s1,s2)->s1.getAge()-s2.getAge()==0?s1.getName().compareTo(s2.getName()):s1.getAge()-s2.getAge());
String s = null;
while ((s=br.readLine())!=null){
String[] split1 = s.split(",");
//把按照切分出来的数组的第1个值作为name,第二个值作为age创建学生对象,并按照年龄排序
Student stu = new Student(split1[0],Integer.parseInt(split1[1]));
set.add(stu);
}
//创建输出流,并把set集合中的学生信息重新写入1.txt文件中;(重写Student的toString方法了)
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
for (Student stu : set) {
bw.write(stu.toString());
bw.newLine();//换行,不用考虑系统问题,比写\r\n更通用
}
br.close();
bw.close();
System.out.println("排序已完成");
}
public class Student{
private String name;
private int age;
public String toString() {
return name +","+age;
}
--自己补上构造方法,getter/setter方法,hashCode和equals方法--
}
题目3[综合练习1]
完成随机点名器案例;
要求:
1:学生姓名都提前写在文件中;
2:每次敲回车,随机显示一个学生姓名,每人最多显示一次,所有人都显示完了就结束程序;
3:输入over结束程序;
效果:
参考代码:
//存学生姓名
private static ArrayList<String> list=new ArrayList<>();
//静态代码块是为了读txt中的数据进入集合中
static {
try {
FileReader fr = new FileReader("stu.txt");
BufferedReader bf = new BufferedReader(fr);
while (true){
String s = bf.readLine();
if(s!=null&&s.trim().length()>0){
list.add(s);
}else {
break;
}
}
//随机打乱顺序
Collections.shuffle(list);
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
System.out.println("今日第1位幸运学生是:"+list.remove(0));
Scanner sc = new Scanner(System.in);
int i=2;
while (true){
System.out.println("回车查看下一位同学,输入over结束程序:");
String s=sc.nextLine();
if("over".equalsIgnoreCase(s)){
System.out.println("谢谢使用,拜拜!");
return;
}
//如果集合中没有数据了,也要结束程序
if(list.size()==0){
System.out.println("所有学生已经全部点名一遍了;");
return;
}
//输入的既不是over而且集合中的数据还大于0,那么就可以移除最大索引的元素,作为幸运学生了
System.out.println("今日第"+i++ +"位幸运学生是:"+list.remove(list.size()-1));
}
}
题目4[综合练习2]
假如config.properties文件上有如下信息.
username=zs
password=123
color=red
请使用键盘录入要登陆的用户名和密码.判断是否正确打印登陆成功和登陆失败.
要求:
如果登陆成功要读取该用户的color属性的值.
如果color=red 以红色字体把用户所有信息打印到控制台. // System.err.println(prop);
如果color=black 以黑色字体把用户所有信息打印到控制台. // System.out.println(prop);
效果:
public static void main(String[] args) throws Exception {
//让用户输入信息
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请输入用户名:");
String name = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
//从配置文件中获取正确的用户信息
FileReader fr = new FileReader("config.properties");
Properties p = new Properties();
p.load(fr);
//判断用户名和密码是否正确并提示信息
String username = p.getProperty("username");
String password2 = p.getProperty("password");
if (username.equals(name) && password2.equals(password)) {
//说明用户名密码正确
String col = p.getProperty("username");
if("red".equals(p.getProperty("color"))){
System.err.println("亲爱的,"+ name+",登录成功,您的信息如下:");
System.err.println(p);
}else {
System.out.println("亲爱的,"+ name+",登录成功,您的信息如下:");
System.out.println(p);
}
break;
}else {
System.out.println("登录失败,用户名或密码不对呀!");
}
}
}