Properties类、缓冲流、转换流、序列化流、装饰者模式、commons-io工具包

day11【Properties类、缓冲流、转换流、序列化流、装饰者模式、commons-io工具包】

昨天内容:
	FileOutputStream: 文件的字节输出流
        public void close();
		public void flush();
		public void write(int b);
		public void write(byte[] bs);
		public void write(byte[] bs,int off,int len);
    FileInputStream: 文件的字节输入流
        public void close();

		public int read();
		public int read(byte[] bs);
    FileWriter: 文件的字符输出流
        public void close();
		public void flush();

		public void write(int ch);
		public void write(char[] chs);
		public void write(char[] chs,int off,int len);

		public void write(String str);
		public void write(String str,int off,int len);
    FileReader: 文件的字符输入流    
        public void close();

		public int read();
		public int read(char[] chs);
今日内容:
	*Properties类(后期作为框架的配置文件)
     缓冲流
     转换流
     序列化流
     打印流
     commons-io框架(工具包)  
     装饰设计模式   

一.IO流的异常处理

1.JDK7之前的标准IO处理
/**
* JDK1.7之前的处理
*/
public static void method01() {
    //1.创建流
    FileReader fr = null;
    try {

        fr = new FileReader("1.txt");
        //2.读数据
        int ch = fr.read();

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.释放资源
        try {
            if (fr != null) {
                fr.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
2.JDK7引入的IO处理
/**
	* JDK1.7以及之后的处理
	* try-with-resource
	*/
public static void method02() {
    try (FileReader fr = new FileReader("1.txt");其他资源) {
        int ch = fr.read();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

二.Properties类

1.Properties类的介绍
Properties 类表示一个持久的属性集
	集: 它是一个集合    
    属性集: 就是一个键值对的集合(本质就是一个Map,但是属性名和属性值都是String类型)
    持久的: 该属性集可以直接和磁盘交互(该类含有直接写数据和读数据的方法)    
2.构造方法
public Properties(); -- 创建一个空的属性集合

public class PropertiesDemo {
    public static void main(String[] args) {
        //1.创建一个持久的属性集
        Properties ps = new Properties();
        System.out.println(ps);
        
    }
}    
3.基本保存数据的方法
public Object setProperty(String key,String value); -- 相当于put方法
public Set<String> stringPropertyNames();  -- 相当于keySet方法  
public String getProperty(String propertyName); -- 相当于get方法   
    
public class PropertiesDemo {
    public static void main(String[] args) {
        //1.创建一个持久的属性集
        Properties ps = new Properties();
        System.out.println(ps);
        //2.添加数据
        ps.setProperty("xiaomi","1999");
        ps.setProperty("huawei","2999");
        ps.setProperty("sanxing","3999");
        ps.setProperty("apple", "4999");
        //3.遍历,stringPropertyNames
        Set<String> propertyNames = ps.stringPropertyNames();
        System.out.println(propertyNames);
        //4.循环
        for (String propertyName : propertyNames) {
            String propertyValue = ps.getProperty(propertyName);
            System.out.println(propertyName+"="+propertyValue);
        }
    }
}    
4.持久化的方法
public void store(OutputStream/Writer,String comments); -- 将Properties中的数据保存到磁盘
    
    //5.保存ps中数据
    FileOutputStream fos = new FileOutputStream("1.properties");
    ps.store(fos,"this is a test file");
    fos.close();

public void load(InputStream/Reader); -- 将文件中的数据,加载到Properties对象中
    //6.从文件中加载数据
    System.out.println("=============");
    Properties ps1 = new Properties();
    System.out.println(ps1);
    FileInputStream fis = new FileInputStream("1.properties");
    ps1.load(fis);
    fis.close();
    System.out.println(ps1);

注意:
	a.规范,如果是Properties保存数据的文件,建议以.properties为后缀
    b.Properties的load方法,只能读取符合Properties保存的那种文件格式    

三.缓冲流

1.缓冲流的作用
缓冲流也称为高效流,是普通流的增强(性能方法)
2.缓冲(Buffered)流的分类
字节输入流 --> 缓冲字节输入流:BufferedInputStream
字节输出流 --> 缓冲字节输出流:BufferedOutputStream
    
字符输入流 --> 缓冲字符输入流:BufferedReader
字符输出流 --> 缓冲字符输出流:BufferedWriter  
所以,在创建缓冲流时,构造方法需要传入普通流对象    
3.字节缓冲流的介绍和使用
  • 字节缓冲流的构造

    public BufferedInputStream(InputStream in); -- 创建字节缓冲输入流,需要传入普通的字节输入流
    public BufferedOutputStream(OutputStream out); -- 创建字节缓冲输出流,需要传入普通的字节输出流
    
  • 字符缓冲流的高效测试

    public class BufferedDemo01 {
        public static void main(String[] args) throws IOException {
            long start = System.currentTimeMillis();
            copy02();
            long end = System.currentTimeMillis();
            System.out.println("耗时:" + (end - start) + "毫秒");
        }
        /**
         * 复制文件:使用缓冲流
         * 耗时:170毫秒
         */
        public static void  copy02()throws IOException {
            //1.创建两个缓冲流
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.png"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy02.png"));
            //2.复制文件
            int b = 0;
            while ((b = bis.read()) != -1) {
                bos.write(b);
            }
            //2.释放资源
            bos.close();
            bis.close();
        }
    
    
        /**
         * 复制文件:使用普通流
         * 耗时:33261毫秒
         */
        public static void copy01() throws IOException {
            //1.创建两个流
            FileInputStream fis = new FileInputStream("1.png");
            FileOutputStream fos = new FileOutputStream("copy.png");
            //2.复制(单个字节,字节数组)
            int b = 0;
            while ((b = fis.read()) != -1) {
                fos.write(b);
            }
            //3.释放资源
            fos.close();
            fis.close();
        }
        //如果使用缓冲流+数组复制,效果更佳
            /**
         * 复制文件:使用缓冲流,再加上数组复制
         * 耗时:13毫秒
         */
        public static void  copy03()throws IOException {
            //1.创建两个缓冲流
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.png"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy02.png"));
            //2.复制文件
            byte[] bs = new byte[1024 * 100];
            int len = 0;
            while ((len = bis.read(bs)) != -1) {
                bos.write(bs, 0, len);
            }
            //2.释放资源
            bos.close();
            bis.close();
        }
    }
    
4.字符缓冲流的介绍和使用
  • a.字符缓冲流的构造

    public BufferedReader(Reader r); -- 创建缓冲字符输入流,需要传入普通的字符输入流
    public BufferedWriter(Writer w); -- 创建缓冲字符输出流,需要传入普通的字符输出流   
    
  • b.字符缓冲流的2个特有方法

    BufferedReader 缓冲字符输入流,特有方法
        public String readLine(); -- 一次读取一行
        
    	/**
         * 字符缓冲输入流:BufferedReader的特有方法
         */
        public static void read()throws IOException {
            //1.创建BufferedReader对象
            BufferedReader br = new BufferedReader(new FileReader("1.txt"));
            //2.读数据
            //String line = br.readLine();
            //System.out.println(line);
            //==========一次读取一行的标准循环代码===========
            String line = null; //保存每次读到的一行数据
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            //3.释放资源
            br.close();
        }    
        
    BufferedWriter 缓冲字符输入流,特有方法
        public void newLine(); -- 写入一个跨平台的换行符
        
        /**
         * 字符缓冲输出流:BufferedWriter的特有方法
         */
        public static void write() throws IOException {
            //1.创建BufferedWriter对象
            BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
            //2.写数据
            for (int i = 0; i < 10; i++) {
                bw.write("php");
                //写一个跨平台的换行
                bw.newLine();
            }
            //3.释放资源
            bw.close();
        }
    
5.综合练习:文本排序
需求:将文本文件中的内容读出,并按照序号排序,最后写入到一个新的文本文件中
 
/**
 * 文本排序
 */
public class BufferedDemo03 {
    public static void main(String[] args) throws IOException {
        ArrayList<String> arr = new ArrayList<String>();
        //1.读文件
        BufferedReader br = new BufferedReader(new FileReader("csb.txt"));
        String str = null;
        while ((str = br.readLine()) != null) {
            arr.add(str);
        }
        br.close();
        //2.排序
        Collections.sort(arr, (o1, o2) -> o1.charAt(0) - o2.charAt(0));
        //3.写文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("new.txt"));
        for (String line : arr) {
            bw.write(line);
            //写一个跨平台的换行
            bw.newLine();
        }
        bw.close();
    }
}    

四.转换流

1.字符编码(编码和解码)
一套规则,每个字符和对应的码值之间转换的规则
    
编码: 将字符 转成 对应的码值
解码: 将码值 转成 对应的字符  

2.字符集
是一个系统支持的所有字符的集合(包括文字,标点,图形)  
常见的字符集和字符编码:
	ASCII字符集,包含美国国家的字符,符号,图形等
        其对应的字符编码,称为ASCII编码,在ASCII编码中所有的字符只占一个字节
        
    GBxxxx字符集: 
		GB2312字符集,包含常见的中文(大概7000多个)
        GBK字符集, 包含大部分的中文以及日韩文字以及繁体文字(大概20000多个)
        GB18030字符集,包含基本上所有的中文,生僻字等(大概70000多个)
        GBXxxx字符集,对应的字符编码:GBK编码,在GBK编码中一个中文占2个字节
            
	Unicode字符集(万国字符集):
		基本上包含了全球所有国家的文字,符号等
        该字符集对应的编码: Unicode编码.UTF-8编码,UTF-16编码,UTF-32编码
        在UTF-8编码中,一个中文占3个字节  
    ========================================================        
    = "总结:对于中国人来说:									=
	=		ASCII编码,一个英文占一个字节					   =
    =        GBK编码,一个中文占2个字节						=
    =        UTF-8编码,一个中文占3个字节    					=
	========================================================	
    ISO-8859-1字符集:
			拉丁字符集(西欧国家的字符集)
            其对应的编码称为ISO-8859-1编码   
            因为我们以后的服务器Tomcat7默认使用ISO-8859-1编码                           
3.编码引出的问题
IDEA读取中文默认使用UTF-8编码
windows默认使用GBK编码
    
假设windows上有一个文件:gbk.txt(GBK编码),内容是:你好
使用IDEA默认UTF-8编码去读:
	public class GBKAndUTF8Demo {
        public static void main(String[] args) throws IOException {
            //1.windows中一个文件gbk.txt,默认使用GBK编码,一个中文2个字节
            //2.IDEA默认使用Utf-8编码,一个中文3个字节
            //3.这时如果用IDEA去读取gbk.txt文件就会出现乱码
            FileReader fr = new FileReader("gbk.txt");
            int ch = fr.read();
            System.out.println((char)ch);
            fr.close();
        }
    }
结果肯定会出现乱码!!!!
    
如何解决这个乱码问题:
	1.强制要求用户的文件,必须使用UTF-8(使用Notepad++打开,选择UTF-8无BOM编码)
    2.可以修改IDEA默认编码,将编码改为GBK    
        
    3.能不能通过代码指定编码,在读取文件中同时指定使用何种编码????
        	可以!! 使用转换流!!!转换流和普通流区别就在于可以自由指定编码
4.使用转换流InputStreamReader解决中文问题
转换输入流:
	InputStreamReader  extends Reader
  • 构造方法

    public InputStreamReader(InputStream in); -- 创建转换输入流,传入普通的字节输入流用于指定文件
    public InputStreamReader(InputStream in,String charsetName);  -- 创建转换入流,指定文件,指定读取时使用何种编码  
    
  • 使用InputStreamReader读取不同编码的文件(代码演示)

    public class GBKAndUTF8Demo02 {
        public static void main(String[] args) throws IOException {
            //1.创建转换输入流
    //        InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK"); // 指定编码GBK
            InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"),"UTF-8"); // 指定编码UTF-8
    
            //2.读数据
            int ch = isr.read();
            System.out.println((char)ch);
    
            ch = isr.read();
            System.out.println((char)ch);
    
            ch = isr.read();
            System.out.println((char)ch);
    
            //3.释放资源
            isr.close();
        }
    }
    
5.使用转换流OutputStreamWriter写中文
转换输出流:
	OutputStreamWriter extends Writer
  • 构造方法

    public OutputStreamWriter(OutputStream out); -- 创建转换输出流,指定输出的目的地,默认UTF-8编码
    public OutputStreamWriter(OutputStream out,String charsetName);-- 创建转换输出流,指定输出的目的地,同时指定输出的编码     
    
  • 输出指定编码的中文

    public class GBKAndUTF8Demo03 {
        public static void main(String[] args) throws IOException {
           //1.创建转换输出流
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("newUTF.txt"),"UTF-8");
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("newGBK.txt"),"GBK");
            //2.写数据
            osw.write("你好");
            //3.释放资源
            osw.close();
        }
    }
    
6.练习:转换文件编码
将GBK编码的文本文件,转换为UTF-8编码的文本文件
a.先指定GBK编码,读出GBK文件
b.再指定UTF_8编码,写出UTF-8文件即可
c.循环
    
public class GBKAndUTF8Demo04 {
    public static void main(String[] args) throws IOException {
        //1.创建转换输入流,用于读GBK文件
        InputStreamReader isr = new InputStreamReader(new FileInputStream("GBK.txt"), "GBK");
        //2.创建输出流,用于写UTF-8文件
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF8.txt"), "UTF-8");
        //3.复制文件
        int ch = 0;
        while ((ch = isr.read()) != -1) {
            osw.write(ch);
        }
        //4.释放资源
        osw.close();
        isr.close();
    }
}    

五.序列化流

1.什么是序列化流
序列化流以对象为单位来操作的
    序列化流: 也称为对象的输出流,写对象,ObjectOutputStream
    反序列化流: 也称为对象的输入流,读对象,ObjectInputStream              
2.ObjectOutputStream的介绍和使用
序列化流,写对象
  • 构造方法

    public ObjectOutputStream(OutputStream out); -- 创建序列化流,传入普通字节输出流   
    
  • 序列化操作的前提

    被序列化的类必须使用java.io.Serializable接口,以启用其序列化功能
    该接口没有任何方法,是一个标记接口    
    
  • 序列化操作(代码演示)

    public class ObjectOutputStreamDemo {
        public static void main(String[] args) throws IOException {
            //1.创建一个序列化流对象
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("2.txt"));
            //2.写对象
            Dog dd = new Dog(2, "旺财");
            //NotSerializableException
            oos.writeObject(dd);
            //3.释放资源
            oos.close();
        }
    }
    
3.ObjectInputStream的介绍和使用
反序列化流,读对象
  • 构造方法

    public ObjectInputStream(InputStream in);
    
  • 反序列操作(正常演示)

    public class ObjectInputStreamDemo {
        public static void main(String[] args) throws Exception {
            //1.创建一个反序列化流
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("2.txt"));
            //2.读对象
            Object obj = ois.readObject();
            System.out.println(obj);
            //3.释放资源
            ois.close();
        }
    }
    注意:
    	a.反序列流只能读序列化流写成的文件
        b.readObject返回的是Object类型,具体是什么类型由序列化流写入时对象的类型决定的    
    
  • 反序列化操作的两种错误演示

    a.ClassNotFoundException 类没有找到异常
        原因: 序列化之后,反序列号之前,将类删除
    b.InvalidClassException 无效类异常
        原因: 序列化之后,反序列号之前,将类进行的修改,这时类就无效了  
     
    扩展1:        
    类是否有效,通过一个序列化版本号来判定的,序列化版本号通过类的内容计算而来
    扩展2:
    Java允许程序员自己管理序列化版本号,只需要在类中定义一个变量,即可,变量必须是以下格式
        public static final long serialVersionUID =;
    	版本号是否修改,完全由程序员自己控制
    扩展3:
    	瞬态关键字transient
        transient用于修饰类的成员变量,transient修饰的成员变量和普通成员变量没有任何区别!!transient修饰的成员变量,在序列化时会自动忽略         
    
4.练习:如果需要序列化多个对象怎么操作?
注意: 序列化流写多个对象是可以的
     反序列化读多个对象时,读不到对象直接抛出异常
    
所以我们不想一次写多个对象,一次读多个对象
    
解决方案: 创建一个集合,添加多个对象,然后操作该集合即可
    
/**
 * 读写多个对象
 */
public class ObjectStreamDemo {
    public static void main(String[] args) throws Exception {
        readObjects();
    }
    /**
     * 读集合
     */
    public static void readObjects() throws Exception {
        //1.创建一个反序列化流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt"));
        //2.读对象
        ArrayList<Dog> arr = (ArrayList<Dog>) ois.readObject();
        for (Dog dog : arr) {
            System.out.println(dog);
        }
        //3.释放资源
        ois.close();
    }
    /**
     * 写集合
     */
    public static void writeObjects() throws IOException {
        //1.创建一个集合,添加多个对象,然后操作该集合即可
        ArrayList<Dog> dogs = new ArrayList<Dog>();
        dogs.add(new Dog(1, "旺小财"));
        dogs.add(new Dog(2, "旺中财"));
        dogs.add(new Dog(3, "旺大财"));
        dogs.add(new Dog(4, "旺老财"));
        dogs.add(new Dog(5, "旺死财"));

        //2.将集合作为一个对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt"));
        //3.写对象
        oos.writeObject(dogs);
        //4.释放资源
        oos.close();
    }
}    

六.打印流

1.打印流PrintStream的介绍
打印流可以快速打印各种数据类型,并且打印流不会抛出IOException异常
特点:
	a.所见即所得
    b.不会抛出IOException异常   
2.PrintStream的构造和常用方法
构造方法:
	public PrintStream(String path);
	public PrintStream(File file);
	public PrintStream(OutputStream out); 
	
打印方法:
	public void print(各种数据类型); -- 不带换行的打印
	public void println(各种数据类型); -- 自动换行的打印
        
public class PrintStreamDemo {
    public static void main(String[] args) throws Exception {
        //1.创建一个打印流
        PrintStream ps1 = new PrintStream("ps.txt");
//        PrintStream ps2 = new PrintStream(new File("ps.txt"));
//        PrintStream ps3 = new PrintStream(new FileOutputStream("ps.txt"));
        //2.打印各种数据类型(所见即所得)
//        ps1.print(97);
//        ps1.print('a');
//        ps1.print(3.14);
//        ps1.print(true);
//        ps1.print("HelloWorld");

        ps1.println(97);
        ps1.println('a');
        ps1.println(3.14);
        ps1.println(true);
        ps1.println("HelloWorld");

        //3.释放资源
        ps1.close();
    }
}        
3.扩展_修改打印流的流向(了解)
public class PrintStreamDemo02 {
    public static void main(String[] args) throws Exception {
        System.out.println("HelloWorld");

//        PrintStream ps = System.out;
//        ps.println("Java");
//        ps.println("PHP");
//        ps.println("ISO");
        //修改打印流的流向
        PrintStream ps = new PrintStream("ps.txt");
//        System.out = ps;
        System.setOut(ps);
        //这些内容不会打印到控制台
        System.out.println("HelloWorld");
        System.out.println("HelloWorld");
        System.out.println("HelloWorld");
        System.out.println("HelloWorld");
        System.out.println("HelloWorld");
    }
}

第七章 装饰设计模式

1.装饰模式作用
可以在不改变原有类,不是用继承的基础上对一个类的方法进行增强
2.装饰者设计模式的4个基本步骤
  • 装饰类和被装饰类必须实现相同的接口
  • 在装饰类中必须传入被装饰类的引用
  • 在装饰类中对需要扩展的方法进行扩展
  • 在装饰类中对不需要扩展的方法调用被装饰类中的同名方法
3.代码实现
/**
 * 装饰类和被装饰类需要实现的接口
 */
public interface SingerInterface {
    /**
     * 唱歌方法
     */
    void sing();

    /**
     * 跳舞方法
     */
    void dance();
}

/**
 * 原有类:被装饰的类
 */
public class LiuDeHua implements SingerInterface{
    @Override
    public void sing() {
        System.out.println("啊哈,给我一杯忘情水~~~");
    }

    @Override
    public void dance() {
        System.out.println("蹦恰恰蹦恰恰蹦恰恰~~~");
    }
}

/**
 * 装饰类
 */
public class LiuDeHuaWapper implements SingerInterface{
    /**
     * LiuDeHua对象
     */
    private LiuDeHua liuDeHua;

    public LiuDeHuaWapper(LiuDeHua liuDeHua) {
        this.liuDeHua = liuDeHua;
    }

    @Override
    public void sing() {
        System.out.println("喝口水,润喉...");
        liuDeHua.sing();
        System.out.println("吃个糖,宝喉...");
    }

    @Override
    public void dance() {
        liuDeHua.dance();
    }
}

public class TestDemo {
    public static void main(String[] args) {
        //1.创建一个刘德华对象
        LiuDeHua liuDeHua = new LiuDeHua();

        //2.创建一个刘德华装饰类对象
        LiuDeHuaWapper wapper = new LiuDeHuaWapper(liuDeHua);

        //3.调用装饰类的方法
        wapper.sing();
        wapper.dance();
    }
}

第八章 commons-io工具包

1.commons-io的介绍和下载
commons-io工具包,专门用于封装各种IO操作,由第三方公司(Apache)开发
下载地址:http://commons.apache.org/proper/commons-io/	

解压后我们只需要用到:commons-io.jar(字节码文件压缩包)
2.常用API介绍
  • 复制文件API(IOUtils工具类)

    public static int copy(InputStream in, OutputStream out); 复制小文件(2GB以下)
    public static long copyLarge(InputStream in, OutputStream out);复制大文件(2GB以上)    
    
    public class CommonsIODemo {
        public static void main(String[] args) throws IOException {
            //1.复制文件
            IOUtils.copy(new FileInputStream("222.png"),new FileOutputStream("copy.png"));
            IOUtils.copyLarge(new FileInputStream("222.png"),new FileOutputStream("copy22.png"));
        }
    }     
    
  • 复制文件到某个文件夹下(FileUtils工具类)

    public static void copyFileToDirectory(File srcFile, File destFile);
    
    
    public class CommonsIODemo {
        public static void main(String[] args) throws IOException {
            //2.复制文件到某个文件夹下
            FileUtils.copyFileToDirectory(new File("222.png"),new File("K:\\其他"));
        }
    }
    
    
    
  • 复制文件夹API(FileUtils工具类)

    public static void copyDirectoryToDirectory(File file1,File file2);
    
    public class CommonsIODemo {
        public static void main(String[] args) throws IOException {
            //3.复制文件夹到某个文件夹下
            FileUtils.copyDirectoryToDirectory(new File("E:\\heima126\\day11"),new File("K:\\其他"));
        }
    }
    
    总结
    "能够使用Properties的load方法加载文件中配置信息
    能够使用字节缓冲流读取数据到程序
    能够使用字节缓冲流写出数据到文件
    能够明确字符缓冲流的作用和基本用法
    "能够使用缓冲流的特殊功能 
    能够阐述编码表的意义
    "能够使用转换流读取指定编码的文本文件
    "能够使用转换流写入指定编码的文本文件
    "能够使用序列化流写出对象到文件
    "能够使用反序列化流读取文件到程序中
    "能够理解装饰模式的实现步骤
    "能够使用commons-io工具包
    

猜你喜欢

转载自blog.csdn.net/qq_41371264/article/details/103864103