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

day17-缓冲流&转换流&序列化流&打印流&Properties

Java中的IO流如何理解——精简

小白学JavaD31》》》IO流 之 缓冲流 & 转换流

字符缓冲流,properties类,序列化流与反序列化流,打印流