Java28缓冲/转换/序列化/打印流,Properties
Posted 码农编程录
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java28缓冲/转换/序列化/打印流,Properties相关的知识,希望对你有一定的参考价值。
文章目录
1.IO流异常处理:文件复制,OIBP
字符流
用于读写文本文件。字节流outputStream(内存->硬盘:写,以内存为中心)
也可以但没字符流FileWriter
封装度高。如下是四个抽象类的其他子类:BufferedOs
:后面Os是outputStream简写。OutputStreamWriter
:是Writer的子类,是FileWriter的父类,没FileWriter封装程度高,暴露了os(字节流)和charset(编码表)。
如下实际开发a.txt(已存在)和b.txt路径由用户指定会发生异常,IO不能直接抛,程序会崩,所以自己处理try catch,不在try中编译异常就是IO异常。
如下改进就在try外面int i = 0;定义+赋值。同理FileInputStream fis = null;
package com.itheima01.exception;
import java.io.*;
/*
* 不论什么类型文件复制都用 字节流!!! 理由:1.没有编解码就不会产生乱码, 用字符流有乱码的风险 * 2.没有编解码复制文件更快。
*
* 如果用字符流复制:GBK编码,utf-8解码,所以在读取时就会产生乱码【如果用字节流复制:读取和写入都没有编解码, 直接就是字节数据的搬运】
* 1. 读取 : a.txt(原本GBK编码,用utf-8解码) (解码: 二进制 -> 字符)
* 中 -> (GBK)20013 20013 -> ? (utf-8解码)
* 2. 写入 : b.txt (编码: 字符 -> 二进制)
* (上面的问号)? -> 10000 (utf-8编码),应该为20013而不是10000
*
* # 异常处理
* try{
* 可能出现异常的代码
* }catch(Exception e){
* }
*/
public class ExceptionDemo {
public static void main(String[] args) { //之前图省事直接在main这行throws IOException
// 外边定义,里面赋值 // 每个变量在使用的时候,必须有值
FileInputStream fis = null;
FileOutputStream fos = null ;
try {
//int i=1/0; //下面fis没有赋上值,所以外面定义时赋null值
fis = new FileInputStream("a.txt"); //刚指定完a.txt,有个程序将a.txt干掉了,出问题:文件找不到,所以IO不能直接抛
fos = new FileOutputStream("b.txt");
int length = -1;
byte[] buffer = new byte[1024];
while((length = fis.read(buffer)) != -1){
fos.write(buffer,0,length);
}
//问题: 如下两行io流用完要及时释放, 如果上面读写的过程中出了异常,下面这段代码就不会执行了,就像水龙头没关,直接跳到catch里
// 解决: finally代码块。try中定义的fis,catch和finally都不会访问到,所以要定义全局变量
// fos.close();
// fis.close();
} catch (IOException e) { //出异常砸盆子,水龙头却没关
e.printStackTrace();
} finally{ //最常见就在这里
if(fos != null){//避免空指针,fos有可能为空(try中值没赋上),空对象调方法产生空指针异常
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
如上代码冗余
package com.itheima01.exception;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
// 多态: 简化代码 所有的IO流都实现了 Closeable 接口 (因为所有的IO流有close方法),选中Closeable按ctrl+h
public class ExceptionDemo02 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null ;
try {
fis = new FileInputStream("a.txt");
fos = new FileOutputStream("b.txt");
int length = -1;
byte[] buffer = new byte[1024];
while((length = fis.read(buffer)) != -1){
fos.write(buffer,0,length);
}
} catch (IOException e) {
e.printStackTrace();
//1111111111111111111111111111111111111111111111111111111111111111111
} finally{
// release(fos);
release(fos,fis); //多态
}
}
private static void release(Closeable... ios) { //可变参数
for (Closeable io : ios) { //遍历数组
if(io != null){ //避免空指针
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package com.itheima01.exception;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* JDK7 特性:
* try...with resource
* try( 要释放的IO流对象A,B) {
* 当这里的代码执行完, A B流就会被自动释放掉(不需要手动调用close)
* }
* 特点: A,B 默认被final所修饰
*/
public class ExceptionDemo03 {
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt")) {
int length = -1;
byte[] buffer = new byte[1024];
while((length = fis.read(buffer)) != -1){
fos.write(buffer,0,length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.字节/字符缓冲流:readLine
package com.itheima02.buffer;
import java.io.*;
/*
* 字节缓冲流:1. public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
public BufferedInputStream(InputStream in, int size)
2. public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。
* 字节缓冲流 底层: 字节流 + 缓存区(默认8k)
* 目的: 用空间(内存)换时间 (提高效率)
* 方法: 构造方法注意一下,需要手动传入一个字节流对象。其他方法都跟父类一样
* 80k(一级) -> 1k(二级)写入到硬盘
*/
public class ByteDemo {
public static void main(String[] args) throws IOException {
FileInputStream is = new FileInputStream("a.txt"); //注意是is不是fis
FileOutputStream os = new FileOutputStream("b.txt");
//如下字节缓存流
BufferedInputStream fis = new BufferedInputStream(is,80*1024);//字符默认8k,这个可以手动调
BufferedOutputStream fos = new BufferedOutputStream(os);
//11111111111111111111111111111111111111111111111111111111111111111111111111111111
int length = -1;
byte[] buffer = new byte[1024]; //这里1kb【二级】最好和上面80k【一级】一致,这样不会有空间浪费问题
while((length = fis.read(buffer)) != -1){
fos.write(buffer,0,length);
}
fos.close();
fis.close();
}
}
package com.itheima02.buffer;
import java.io.*;
/*
* 字符缓冲流:1. 构造
1. public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
2. public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
2. 特有方法
1. BufferedReader: public String readLine() : 读一行文字。
2. BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。
*/
public class CharDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt")); //BufferedReader(字符流),BufferedReader也默认8kb
// String line = br.readLine();
// System.out.println(line);
String line = null;
while((line = br.readLine()) != null){
System.out.println(line); //有几行打印几行
}
br.close(); //关高级流,会默认将低级流也会一并关掉
//11111111111111111111111111111111111111111111111111111111111111111111111111111
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
bw.write("一句话");
bw.write(System.lineSeparator()); //换行
bw.write("一段话");
bw.newLine(); //换行,底层就是上面System.lineSeparator()
bw.write("一翻话");
bw.close();
}
}
3.案例_出师表:\\ \\ . ,content = map.get(i)
package com.itheima02.buffer;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/*
* 需求: 将a.txt中的内容,按照每行的序号进行排序 b.txt
* 1. 先把a.txt中的数据都读出来
* 2. 一次读一行, 进行切割 number -> 语句
*
* 方案A
* 3. 放HashMap <Integer,String> map
* 4. for i 1-9 (i = key) //不需要排序,按序号取出并输出
* value = map.get(key)
*
* 方案B
* 3. 放TreeMap<Integer,String> //TreeMap的key会自动排序的,Integer类型会按自然顺序排,底层是treeset比较器默认自动升序。
* 4. 遍历打印
*/
public class OutTeacherWatchDemo {
public static void main(String[] args) throws IOException {
// method01();
TreeMap<Integer, String> map = new TreeMap<>();
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
String line = null;
while((line = br.readLine()) != null){
String[] split = line.split("\\\\.");
Integer number = Integer.parseInt(split[0]);
String content = split[1];
map.put(number,content);
}
br.close();
BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));
Set<Map.Entry<Integer, String>> entrySet = map.entrySet(); //直接遍历treeMap,输出即可
for (Map.Entry<Integer, String> entry : entrySet) {
Integer key = entry.getKey();
String value = entry.getValue();
bw.write(key + "." + value);
bw.newLine();
}
bw.close();
}
//111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
private static void method01() throws IOException { //方案A
HashMap<Integer, String> map = new HashMap<>();
BufferedReader br = new BufferedReader(new FileReader("a.txt")); //这是读取a.txt的流
String line = null;
while((line = br.readLine()) != null){
String[] split = line.split("\\\\."); // 注意: \\\\. 表示一个. (正则表达式)
Integer number = Integer.parseInt(split[0]); //前面是数字
String content = split[1]; //后面是内容
map.put(number,content);
}
br.close();
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); //这是输出文本的流
for (int i = 1; i <= 9; i++) { // 遍历1~9 -> 指的就是上面的number
String content = map.get(i);
bw.write(i +"." + content);
bw.newLine(); //添加一个换行符
}
bw.close();
System.out.println("复制完成");
}
}
4.转换流:字节字符的中间流
package com.itheima03.transfer;
import java.io.*;
/*
* 案例: 系统文件(GBK 编码) -> 程序(utf-8 解码)
* 乱码: 编解码所使用的编码表不一致。 解决: 将编码和解码编码表一致
*
* 方案A: (最常用)
* 系统文件GBK -> UTF-8
* FileReader 流 搞定
*
* 方案B:
* 程序默认编码表改成GBK (一般不会这么做!!!)
* FileReader 流 搞定
*
* 方案C:
* 将IO流的解码字符集 指定为gbk , 但是程序还是utf-8
* InputStreamReader (在开发中一般也不用, 开发中的涉及的程序和资料都是UTF-8)
*/
public class Demo01 {
public static void main(String[] args) throws IOException {
// FileReader fr = new FileReader("c:/test/a.txt"); //FileReader底层默认编码表utf-8 //与a.txt的GBK会乱码
FileInputStream fis = new FileInputStream("c:/test/a.txt"); //a.txt里内容:写一句话
InputStreamReader fr = new InputStreamReader(fis, "gbk");
int content = -1;
while((content = fr.read()) != -1){
System.out.println((char)content);
}
fr.close();
}
}
package com.itheima03.transfer;
import java.io.*;
/*
* 练习:转换文件编码
1. 将GBK编码的文本文件,转换为UTF-8编码的文本文件。
分析:
1. 读GBK编码文件 : 用GBK编码的字符输入流
1. FileReader : FileInputStream + utf-8 默认 (不行)
2. InputStreamReader : FileInputStream + gbk 指定 (可以)
2. 写utf-8编码文件 : 用utf-8编码的字符输出流
1. FileWriter : FileoutputStream + utf-8 默认(可以)
2. OutputStreamWriter : FileoutputStream + utf-8 指定(可以)。两个都可以, 用FileWriter(简单)
*/
public class Demo02 {
public static void main(String[] args) throws IOException {
InputStreamReader isr
= new InputStreamReader(new FileInputStream("c:/test/a.txt"), "gbk");
// FileWriter fw = new FileWriter("c:/test/b.txt"); //用下行也可以
OutputStreamWriter osw
= new OutputStreamWriter(new FileOutputStream("c:/test/b.txt"), "utf-8");
//111111111111111111111111111111111111111111111111111111111111111111111111
int length = -1;
char[] buffer = new char[1024]; //用的字符流,不是byte[]
while((length = isr.read(buffer)) != -1){
osw.write(buffer,0,length);
}
osw.close();
isr.close(); //运行后产生b.txt utf-8 9字节 , a.txt gbk 6字节
}
}
5.序列化流:oos.writeObject,Serializable
package com.itheima04.serial;
import java.io.*;
/*
* 文本编码: 字符 -> 字节也叫二进制 (目的保存数据)
*
* 序列化(serializable) : 对象/数据结构 -> 二进制 (目的将对象直接保存在硬盘上) 存档
* Base64 编码等 和utf-8和gbk没有关系
*
* 反序列化 : 二进制 -> 对象 (将硬盘上的数据 读到 内存中形成对象) 读档
* Base64 解码
*
public ObjectOutputStream(OutputStream out) : 序列化流
public ObjectInputStream(InputStream in) : 反序列化流
总结: 一个类要允许被序列化:
1. 首先: 实现Serializable接口
2. 其次: 这个类要设置唯一的serialVersionUID (String类源码里也有)
补丁:transient : 瞬态 (关键字),用这个关键字修饰的属性,不允许序列化/反序列化,如密码不希望被保存
*/
public class Demo01 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// method01(); //序
method2(); //反序
}
private static void method2() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object s1 = ois.readObject();// 反序列化 //具体是什么对象, 设计成Object
// Student s1 = (Student) ois.readObject(); //可以,同上行输出一样
System.out.缓冲流 转换流 序列化流
day17-缓冲流&转换流&序列化流&打印流&Properties