Java=缓冲流,转换流,序列化流,打印流(PrintStrean),装饰设计模式,Commons-io工具包

1.缓冲流(高效流,比普通流性能更高)
2.转换流(编码相关的流,指定编码)
3.序列化流(操作对象)
4.打印流(System.out.println()) 
5.设计模式(装饰设计模式,4个步骤)
6.common-io工具包(简化IO的代码)

一。缓冲流

缓冲流也叫高效流,对以前学过的四个基本流的增强(性能,方法上基本一模一样) 

优点:

1)适用于读写文件容量大的文件;

2)在标准字节流的基础上,增加缓冲流;

3)通过改变缓冲区大小或字节数组大小来进行优化;

4)优化指标,程序执行次数或执行时间;

缓冲流的分类:

缓冲字节输入流:BufferedInputStream  ---> 对普通的字节输入流InputStream的增强    
缓冲字节输出流:BufferedOutputStream   ---> 对普通的字节输出流OutputStream的增强  
    
缓冲字符输入流: BufferedReader  ---> 对普通的字符输入流Reader的增强
缓冲字符输出流: BufferedWriter  ---> 对普通的字符输出流Writer的增强

.字节缓冲流的介绍和使用

构造方法:

public BufferedInputStream(InputStream in);//缓冲流的构造需要接收对应普通流
public BufferedOutputStream(OutputStream out);//缓冲流的构造需要接收对应普通流

字符缓冲流的高效测试

public class BufferedDemo01 {
    public static void main(String[] args) throws Exception {
        copy01();
    }
    //缓冲流复制 耗时:950毫秒
    public static void copy01() throws Exception {
        //创建缓冲流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\upload\\666.png"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy01.png"));
        //复制文件
        long start = System.currentTimeMillis();
        int b = 0;
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"毫秒");
        //释放资源
        bos.close();
        bis.close();
    }
    //普通流复制 半天过去了...
    public static void copy02() throws IOException {
        //创建普通字节流
        FileInputStream fis = new FileInputStream("G:\\upload\\666.png");
        FileOutputStream fos = new FileOutputStream("copy.png");
        long start = System.currentTimeMillis();
        //复制,一次一个字节
        int b = 0;
        while ((b = fis.read()) != -1) {
            fos.write(b);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"毫秒");
        //释放资源
        fos.close();
        fis.close();
    }
}

思考: 有没有更快的方式 ??
    有! 使用缓冲流的同时,使用一次读取一个字节数组的方式!!!

字符缓冲流的介绍和使用

构造方法“

public BufferedWriter(Writer w);//需要传入普通的字符流
public BufferedReader(Reader r);//需要传入普通的字符流

字符缓冲流也是对普通字符类的性能增强

字符缓冲流的2个特有方法

BufferedWriter  是 普通Writer的增强
    多了一个特有方法: 写一个换行符(根据系统而定)
			public void newLine();

public class BufferedDemo02 {
    public static void main(String[] args) throws IOException {
        //缓冲字符流
        BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
        //写数据
        for (int i = 0; i < 10; i++) {
            bw.write("java");
            //写入一个换行
            bw.newLine();
        }
        //释放资源
        bw.close();
        //关流的原则:
        //a.先开后关
        //b.流用完了就立刻关闭
    }
}


BufferedReader 是 普通Reader的增强
    多个一个特有方法: 一次读取一行内容
			public String readLine();

public static void main(String[] args) throws IOException {
    //缓冲字符流
    BufferedReader br = new BufferedReader(new FileReader("2.txt"));
    //读数据
    //String line = br.readLine();
    //System.out.println(line);
    //=============一次读取一行的标准循环代码===============
    String line = ""; //用来保存每次读取的一行数据
    /**
         * (line = br.readLine()) != null
         * 以上代码干了三件事!
         * a.读取  br.readLine()
         * b.赋值  line = 读到的一行数据
         * c.判断  line != null
         */
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
    //释放资源
    br.close();
}
注意:
	一次读取一行的标准循环,不会因为有一行为"null"字符串内容或者有一行为""字符串内容而停止
    只有读取到文件的末尾,没有内容返回值null才能停止!!    

综合练习:文本排序

读取文本中的内容,按照序号排序,排序之后从头到尾写入新的文件中
    
public class TestDemo {
    public static void main(String[] args) throws Exception {
        //读取文本中的内容,按照序号排序,排序之后从头到尾写入新的文件中
        ArrayList<String> arr = new ArrayList<String>();
        //1.读取文本中的内容
        BufferedReader br = new BufferedReader(new FileReader("csb.txt"));
        //2.一次读取一行
        String line = "";
        while ((line = br.readLine()) != null) {
            arr.add(line);
        }
        //3.释放资源
        br.close();
        //4.对集合排序
//        Collections.sort(arr, new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                //按照字符串的首字母进行升序
//                return o1.charAt(0) - o2.charAt(0);
//            }
//        });
        Collections.sort(arr, (o1, o2) -> o1.charAt(0) - o2.charAt(0));
        //5.写入到新文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("new.txt"));
        for (String s : arr) {
            bw.write(s);
            bw.newLine();//一句话一行
        }
        bw.close();
    }
}    

二。转换流

编码和解码

编码: 把字符 ----> 字节 ,比如 'a'  ---> 97(0110 0001)
解码: 把字节 ----> 字符 ,比如 97(0110 0001) ---> 'a'    

字符集

字符集: 一个系统支持的所有字符的集合(文字,标点,数字,图形符号等)

字符编码

字符编码: 字符和二进制一一对应的一套规则,比如 字符'a' 对应的码值 97

常见的字符集和字符编码

ASCII字符集  ---> ASCII编码, 规定ASCII字符集中所有的字符都占1个字节
GBK字符集 ---> GBK编码,规定所有中文字符都占2个字节(这两个字节都是负数)
Unicode字符集 ---> UTF-8编码,规定所有中文字符都占3个字节  
    
ISO-8859-1字符集.这是西欧国家的字符集,(我们以后使用Tomcat7以前默认就是使用ISO-8859-1)   

编码引出的问题

IDEA默认使用UTF-8编码,Windows默认使用的GBK编码

public class TestLuanMaDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("GBK.txt");//文件用的GBK编码,一个中文两个字节

        int ch = fr.read(); //IDEA默认UTF-8编码,一个中文3个字节
        System.out.println((char)ch);

        fr.close();
    }
}
以上问题会导致乱码
出现这个问题了,怎么办??
    a.把文件的编码改成UTF-8和IDEA一致
    b.把IDEA的编码改成GBK和文件的一致  
    

使用转换流InputStreamReader解决读取中文的问题

转换输入流 InputStreamReader extends Reader

构造方法

public InputStreamReader(InputStream in,String charsetName);//指定使用何种编码读文件
public InputStreamReader(InputStream in);//使用工具默认的编码去读文件(IDEA默认UTF-8)

使用InputStreamReader读取不同编码的文件

public class TestInputStreamReaderDemo {
    public static void main(String[] args) throws Exception {
        //1.创建InputStreamReader对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"),"UTF-8");
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"),"GBK");
        //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();
    }
}

使用转换流OutputStreamWriter写不同编码的中文

转换输出流OutputStreamWriter extends Writer

构造方法

public OutputStreamWriter(OutputStream out,String charsetName);//写文件时指定编码
public OutputStreamWriter(OutputStream out);//使用工具默认的编码写文本(IDEA是UTF-8)

输出指定编码的中文

public class TestOutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        //1.创建OutputStreamWriter对象
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("newgbk.txt"),"GBK");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("newutf8.txt"),"UTF-8");
        //2.写数据
        osw.write("你好");
        //3.释放资源
        osw.close();
    }
}

转换流的理解

转换文件编码:

需求:将GBK编码的文本文件,转换为UTF-8编码的文本文件。
分析:
	a.先把GBK文件中内容读取出来(指定以GBK编码读取)
    b.再把数据写入到UtF-8文件中(指定以UTF-8编码写入)    
 
 public class TestDemo {
    public static void main(String[] args) throws IOException {
//        需求:将GBK编码的文本文件,转换为UTF-8编码的文本文件。
//        分析:
//        a.先把GBK文件中内容读取出来(指定以GBK编码读取)
        InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
//        b.再把数据写入到UtF-8文件中(指定以UTF-8编码写入)
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF8.txt"),"UTF-8");
        //复制
        int ch = 0;
        while ((ch = isr.read()) != -1) {
            osw.write(ch);
        }
        //释放资源
        osw.close();
        isr.close();
    }
}       

三。序列化流

什么是序列化流

序列化流: 写出对象的流 
    ObjectOutputStream
反序列化流: 读取对象的流  
    ObjectInputStream

.ObjectOutputStream的介绍和使用

构造方法:

public ObjectOutputStream(OutputStream out); //需要接收一个普通的字节输出流

序列化操作的前提

想要序列化必须实现java.io.Serializable 接口
    
该接口中没有方法,该接口一般称为标记接口    

演示:

public class TestObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //1.创建一个ObjectOutputStream对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog.txt"));
        //2.写对象
        Dog dd = new Dog(10,"旺财");
        oos.writeObject(dd);//NotSerializableException
        //3.释放资源
        oos.close();
    }
}
注意: 不用查看dog.txt文件,因为这个文件中的字节数据我们是看不懂的

ObjectInputStream的介绍和使用

构造方法:

public ObjectInputStream(InputStream in);

反序列化操作

public class TestObjectInputStreamDemo {
    public static void main(String[] args) throws Exception {
        //1.创建ObjectInputStream对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog.txt"));
        //2.读对象
        Dog obj = (Dog) ois.readObject();
        System.out.println(obj);
        //3.释放资源
        ois.close();
    }
}



反序列化操作的两种异常:


a.ClassNotFoundException 没有找到类异常
    出现原因:
		序列化之后,反序列化之前,删除了原来序列化的那个类!!
b.InvalidClassException 无效类异常
    出现原因:
		序列化之后,反序列化之前,修改了原来序列化的那个类!!!
            
c.实际上序列化流判断类是否有效通过:serialVersionUID来识别的   


3333如果需要序列化多个对象怎么操作?

注意: 序列化流一个文件只适合序列化一个对象
分析:
	a.把你要序列化的多个对象,保存到一个集合对象
    b.将这个集合作为对象,序列化到文件中
    c.可以从文件中将整个集合反序列化回来
    d.遍历集合把里面的对象一一打印出来
/**
 * 如何序列化多个对象?
 */
public class TestDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        read();
    }

    //序列化多个对象
    public static void write() throws IOException {
//        注意: 序列化流一个文件只适合序列化一个对象
//        分析:
//        a.把你要序列化的多个对象,保存到一个集合对象
        ArrayList<Dog> dogs = new ArrayList<Dog>();
        dogs.add(new Dog(1, "旺财", 4));
        dogs.add(new Dog(2, "来福", 5));
        dogs.add(new Dog(3, "哮天犬", 6));
//        b.将这个集合作为对象,序列化到文件中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt"));
        oos.writeObject(dogs);
        oos.close();

    }

    public static void read() throws IOException, ClassNotFoundException {
//        c.可以从文件中将整个集合反序列化回来
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt"));
        ArrayList<Dog> dogs = (ArrayList<Dog>) ois.readObject();
        ois.close();
//        d.遍历集合把里面的对象一一打印出来
        for (Dog dog : dogs) {
            System.out.println(dog);
        }
    }
}        





单一对象,无继承关系:若想实现序列化与反序列化,则必须实现序列化接口,否则报异常:NotSerializableException

对象间有继承关系,但无引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口或提供无参构造函数,否则报invalidClassException

对象间有继承关系,并且有引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口

存在继承关系时,若想序列化子类对象,一并序列化父类对象,则负责类型必须实现序列化接口或者提供无参构造函数

 

四。打印流

打印流的介绍

a.System.out.println()/print().实际上就是调用了打印流的方法
b.打印流PrintStream   
c.打印流中重写各种数据类型的print和println方法,打印数据时非常方便    
d.打印流不会抛出IOException(会抛出别的Exception)   

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("p.txt");
//        PrintStream ps2 = new PrintStream(new File("p.txt"));
//        PrintStream ps3 = new PrintStream(new FileOutputStream("p.txt"));
        //2.打印数据,所见即所得
        ps1.println('a');
        ps1.println(97);
        ps1.println(true);
        ps1.println(100);
        ps1.println("HelloWorld");
        //3.释放资源
        ps1.close();
    }
}

修改系统打印流的流向

public class PrintStreamDemo02 {
    public static void main(String[] args) throws Exception {
        //1.创建一个打印流
        PrintStream ps1 = new PrintStream("p.txt");
        //2.系统的输出
        System.out.println("Java");
        //3.修改系统打印流的流向
        System.setOut(ps1);
        System.out.println("aJava");
        System.out.println("cJava");
        System.out.println("dJava");
        System.out.println("eJava");
        System.out.println("Java");
      
    }
}

  五。装饰设计模式

.装饰模式作用

装饰模式指的是在不改变原类, 不使用继承的基础上,动态地扩展一个对象的功能。

2.装饰者设计模式的4个基本步骤

  • 装饰类(我们定义的新类)和被装饰类(原类)必须实现相同的接口

  • 在装饰类中必须传入被装饰类的引用

  • 在装饰类中对需要扩展的方法进行扩展

  • 在装饰类中对不需要扩展的方法调用被装饰类中的同名方法

.代码实现

/**
 * 歌星接口
 */
public interface SingStar {
    /**
     * 唱歌方法
     */
    void sing();

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

/**
 * 被装饰类
 */
public class LiuDeHua implements SingStar{
    //唱歌
    public void sing(){
        System.out.println("啊哈,给我一杯水..");
    }

    //跳舞
    public void dance(){
        System.out.println("蹦恰恰蹦恰...");
    }
}

/**
 * LiuDeHua类的装饰类
 */
//1.装饰类(我们定义的新类)和被装饰类(原类)必须实现相同的接口
public class LiuDeHuaWrapper implements SingStar{
    //2.在装饰类中必须传入被装饰类的引用
    private LiuDeHua ldh;

    public LiuDeHuaWrapper(LiuDeHua ldh) {
        this.ldh = ldh;
    }

    @Override
    public void sing() {
        //3.在装饰类中对需要扩展的方法进行扩展
        System.out.println("刘德华在北京唱歌..");
        ldh.sing();
    }

    @Override
    public void dance() {
        //4.在装饰类中对不需要扩展的方法调用被装饰类中的同名方法
        ldh.dance();
    }
}

public class TestDemo {
    public static void main(String[] args) {
        //1.创建被装饰类
        LiuDeHua ldh = new LiuDeHua();
        //2.创建装饰类对象
        LiuDeHuaWrapper wrapper = new LiuDeHuaWrapper(ldh);
        //3.调用装饰类中方法
        wrapper.sing();
        wrapper.dance();
    }
}

六。commons-io工具包

commons-io的介绍和下载

commons-io是Apache公司提供简化IO操作的工具包
我们需要把commons-io工具下载下来:
a.解压
b.在我们模块下创建lib文件夹,将解压后的 commons-io.jar复制进来
c.选中commons-io.jar右键选中Add as Libary 添加到本模块中    

官网地址:http://commons.apache.org/proper/commons-io/

下载 :http://commons.apache.org/proper/commons-io/download_io.cgi


工具类包括FileUtils、IOUtils、FilenameUtils和FileSystemUtils,前三者的方法并没有多大的区别,只是操作的对象不同,故名思议:FileUtils主要操作File类,IOUtils主要操作IO流,FilenameUtils则是操作文件名,FileSystemUtils包含了一些JDK没有提供的用于访问文件系统的实用方法。当前,只有一个用于读取硬盘空余空间的方法可用。

常用API介绍

  • 复制文件API

  • 复制文件夹API

public class TestCommonsDemo {
    public static void main(String[] args) throws IOException {
        //1.IOUtils 适合复制2G大小以下的文件
        IOUtils.copy(new FileInputStream("G:\\up\\1546241961620.png"),new FileOutputStream("copy.png"));

        //2.IOUtils适合复制2G大小以上的文件
        IOUtils.copyLarge(new FileInputStream("G:\\up\\1546241961620.png"), new FileOutputStream("copy1.png"));

        //3.FileUtils 复制文件
        FileUtils.copyFileToDirectory(new File("G:\\up\\1546241961620.png"), new File("G:\\uploads"));
        //4.FileUtils 复制文件夹
        FileUtils.copyDirectoryToDirectory(new File("C:\\Users\\Administrator\\Desktop\\temp\\aaa"),new File("G:\\uploads"));
    }
}

总结:

缓冲流
    字节缓冲流(BufferedOutputStream和BufferedInputStream),没有特有方法,性能比普通流更高
    
    字符缓冲流(BufferedWriter和BufferedReader),有特有方法,性能比普通流更高
    	BufferedWriter: 
			public void newLine();
    	BufferedReader:
			public String readLine();

2.转换流
    转换输出流: 可以指定编码写文件
    	OutputStreamWriter
    	public OutputStreamWriter(OutputStream out,String 指定的编码);
    转换输入流: 可以指定编码读文件
    	InputStreamReader
        public InputStreamReader(InputStream in,String 指定的编码);

3.序列化流
    序列化流:  写对象
		ObjectOutputStream
    	public void writeObject(对象);//该对象的类必须实现java.io.Serializable接口
    反序列化流: 读对象
		ObjectInputStream
        public Object readObject();

other----

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;

/*
    项目根路径下有f.txt文件,内容如下:
		我爱中国
		123456

    请利用IO流的知识读取f.txt文件的内容反转后写入f1.txt文件中,内容如下:
		123456
		我爱中国
 */
public class Test05 {

    public static void main(String[] args) throws IOException {

        // 读取f.txt文件中的内容到内存(集合中保存!)
        ArrayList<String> list = new ArrayList<>();
        BufferedReader br = new BufferedReader(new FileReader("D:/f.txt"));

        String line = null;

        while ((line = br.readLine())!=null){
            list.add(line);
        }

        // 使用集合工具类的方法
        Collections.reverse(list);

        // 写文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:/f1.txt"));

        // 遍历集合
        for (String str : list) {
            bw.write(str);
            bw.newLine();
            bw.flush();
        }

        bw.close();
        br.close();

    }

}
import java.io.*;

/*
    需求:利用高效字节输入流和高效字节输出流完成文件的复制。要求:
        1. 将D盘下的c.png文件复制到D盘下
        2. 采用一次读写一个字节数组方式复制
 */
public class Test02 {

    public static void main(String[] args) throws IOException {

        // 高效输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/c.png"));

        // 高效输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:/c.png"));

        // 读取硬盘数据到内存
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取数据
        while ((len = bis.read(buffer))!=-1){
            // 将读到内存的数据给它写到硬盘中!
            bos.write(buffer,0,len);
        }

        // 关闭流
        bis.close();
        bos.close();
    }

}
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;

/*
    需求:用代码实现一个验证码小程序,要求如下:
        1. 在项目根目录下新建一个文件:data.txt,键盘录入3个字符串验证码,并存入data.txt中,要求一个验证码占一行;
        2. 键盘录入一个需要被校验的验证码,如果输入的验证码在data.txt中存在:在控制台提示验证成功,如果不存在控制台提示验证失败
 */
public class Test02 {

    public static void main(String[] args) throws IOException {

        // 1. 让用户在控制台输入3个验证码,保存到data.txt文件中
        writeCodeToFile();

        // 2. 让用户再输入一个验证码(校验),与data.txt文件中的验证码进行比对(校验)
        verifyCode();
    }

    /*
        让用户再输入一个验证码(校验),与data.txt文件中的验证码进行比对(校验)
     */
    public static void verifyCode() throws IOException {
        // 创建一个文件缓冲流对象
        BufferedReader br = new BufferedReader(new FileReader("D:/data.txt"));

        // 创建一个集合用于存储读取的数据
        ArrayList<String> list = new ArrayList<>();

        // 读数据
        String line = null;
        while ((line = br.readLine())!=null){
            // 将读到的数据添加到集合中去
            list.add(line);
        }

        // 让用户再输入一个验证码
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入被校验的验证码:");
        String code = scanner.nextLine();

        // 校验
        if(list.contains(code)){
            System.out.println("校验成功!");
        }else{
            System.out.println("校验失败!");
        }

    }

    /*
        让用户在控制台输入3个验证码,保存到data.txt文件中
     */
    public static void writeCodeToFile() throws IOException {
        // 提供一个文件缓冲流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("D:/data.txt")));

        // 键盘录入
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            System.out.println("请输入第"+(i+1) + "个验证码:");
            String line = scanner.nextLine();
            // 将其写入到data.txt文件中去
            bw.write(line);
            // 换行
            bw.newLine();
        }
        // 关闭流
        bw.close();
    }

}
发布了117 篇原创文章 · 获赞 20 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/u010581811/article/details/105057990
今日推荐