Java 实训 十四天 IO流
Java IO流
一、转换流
1、定义
将字节流转换为字符流(就是在字节流的基础上,增加编码器解码器)
2、转换器
InputStreamReader -》字节输入流转化为字符输入流
构造:
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)
OutputStreamWriter -> 字节输出流转化为字符输出流
构造:
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)
案例代码:自定义扫描器并实现readLine()方法
class MyScanner{
private InputStream in;
public MyScanner(InputStream in) {
this.in = in;
}
public String readLine() throws Exception{
//将字节输入流转为字符输入流
InputStreamReader inputStreamReader = new InputStreamReader(this.in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
return bufferedReader.readLine();
}
}
二、PrintStream、PrintWriter
这两个类也属于包装器的一种
PrintStream: 可以用于包装OutputStream
PrintWriter: 可以包装一个Writer
包装后的对象可以调用相应的print方法实现在控制台打印输出:
print();
println();
案例代码:通过打印流将内容打印到文件
//指定打印的目标地址
FileWriter fileWriter = new FileWriter("D:\\test\\content.txt");
PrintWriter out = new PrintWriter(fileWriter, true);
out.println("hello world");
out.println("这是打印流");
三、Properties
1、定义
Properties表示属性集,通常伴随以properties作为后缀的属性配置文件出现。
在properties文件中,每一行都是一个配置项,并且是以键值对形式出现,例如:
server.port=8080
2、构造方法
Properties()
Properties(Properties defaults)
3、常用方法
Object setProperty(String key, String value) //设置属性
String getProperty(String key) //获取属性
void list(PrintStream out)
void load(InputStream inStream) //载入属性文件
void load(Reader reader)
void store(OutputStream out, String comments) //存储
void store(Writer writer, String comments)
4、操作案例
//构建properties属性配置文件对象
Properties properties = new Properties();
//构建属性文件的字节输入流
InputStream resourceAsStream = Day14Demo03.class.getClassLoader().getResourceAsStream("application.properties");
//载入属性文件
properties.load(resourceAsStream);
//读取属性文件中的配置项
String port = properties.getProperty("server.port");
//修改服务器监听端口为80
properties.setProperty("server.port", "80");
//获取属性文件中的所有配置
for (Map.Entry<Object, Object> entry:properties.entrySet()) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
/*//修改完配置后需要重写属性文件
//构造一个字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\Java\\workspace\\test\\resources\\application.properties");
properties.store(fileOutputStream, "修改服务器的监听端口"); //将内存中已经修改好的属性内容重写到目标文件
//关流
fileOutputStream.close();
resourceAsStream.close();*/
四、合并流
1、定义
将多个打开流合并为一个。
2、类及构造
构造:
SequenceInputStream(InputStream s1, InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
3、合并流案例
Vector<InputStream> logs = new Vector<>();
//创建日志1的输入流
FileInputStream log1 = new FileInputStream(pathPre + "20240407-1.log");
FileInputStream log2 = new FileInputStream(pathPre + "20240407-2.log");
FileInputStream log3 = new FileInputStream(pathPre + "20240407-3.log");
//添加准备合并的输入流
logs.add(log1);
logs.add(log2);
logs.add(log3);
//InputStream sequenceInputStream = new SequenceInputStream(log1, log2);
SequenceInputStream sequenceInputStream = new SequenceInputStream(logs.elements());
//转换流
InputStreamReader inputStreamReader = new InputStreamReader(sequenceInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while (true){
String msg = bufferedReader.readLine();
if (Objects.isNull(msg)){
break;
}
System.out.println(msg);
}
练习:将如下多个文件中的学生报道信息通过合并流读取并提取时间,姓名和地址。输出到控制台
students-info1.txt
[2023-6-15] 张三 16 成都
[2023-6-26] 李四 21 绵阳
students-info2.txt
[2023-9-1] 王五 19 宜宾
[2023-9-10] 赵六 20 广州
students-info3.txt
[2023-11-06] 田七 18 上海
[2023-12-11] 猪八 18 西昌
五、其他IO流
1、ByteArrayInputStream、ByteArrayOutputStream
目的地是一个可变长度的字节数组的字节输入流、字节输出流 -- 目的地是内存的字节流
构造:
ByteArrayOutputStream()
方法:
void write(int b)
void write(byte[] b, int off, int len)
byte[] toByteArray()
2、StringReader、StringWriter
StringWriter 目的地是一个字符串的输出流
StringReader 数据的来源是一个字符串的输入流
六、对象序列化/反序列化
序列化(钝化):
1、定义
ObjectOutputStream 将内存中的对象序列化到流中
2、类信息
构造方法:
ObjectOutputStream(OutputStream out)
方法:
void writeObject(Object obj)
注意:
如果对象需要序列化,则对应的类必须实现Serializable接口!
案例代码:将Student对象序列化到本地文件中
String path = "D:\\test\\logs\\Student.txt";
//实例化对象
Student student = new Student("张三", 18, "成都", "15698457412");
//构造文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(path);
//序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(student);
objectOutputStream.close();
fileOutputStream.close();
反序列化(活化):
1、定义
ObjectInputStream 可以将流中的序列化的对象信息反序列化为对象
2、类信息
构造方法:
ObjectInputStream(InputStream in)
方法:
Object readObject()
案例代码:将Student序列化后的文件,反序列化为对象
String path = "D:\\test\\logs\\Student.txt";
//转化为输入流
FileInputStream fileInputStream = new FileInputStream(path);
//反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Student student = (Student) objectInputStream.readObject();
//打印对象信息
System.out.println(student);
总结:
* 静态成员不能被序列化
* transient修饰的成员会被忽略
* 被Serializable接口修饰的类在被编译为.class时会被标记一个独一无二的serialVersionUID,
利用这个id在反序列化时进行检查,保证只有完全一致的类才能反序列化,从而保证安全性。
* 我们也可以自己定义serialVersionUID,从而自己控制序列化和反序列化的安全检查,实现,
在类只有轻微改动的情况下,仍然可以实现反序列化的功能。