22.通配符、IO流

1. 通配符的使用

1.1 无限制条件的通配符:?

@Test
    public void test1(){

        ArrayList<?> list1;
        ArrayList<Person> list2 = new ArrayList<Person>();
        ArrayList<Student> list3 = new ArrayList<Student>();

        //合法
        list1 = list2;
//        list1 = list3;

        //写入:list1是否可以添加数据? 不可以的
//        list1.add(new Person());

        //特例:
        list1.add(null);

        //读取:可以
        list2.add(new Person());
        Object obj = list1.get(1);
        System.out.println(obj);
    }

1.2 有限制条件的通配符的使用

/*
    *  ?
    *
    * ? extends T : A<? extends T> 可以看做是A<T>和 A<G>的父类。其中G类是T类的子类
    *
    * ? super Person: A<? super T> 可以看做是A<T>和 A<G>的父类。其中G类是T类的父类
    *
    * */
    @Test
    public void test2(){
        ArrayList<? extends Person> list1 ;
        ArrayList<? super Person> list2;

        ArrayList<Object> list3 = new ArrayList<Object>();
        ArrayList<Person> list4 = new ArrayList<Person>();
        ArrayList<Student> list5 = new ArrayList<Student>();

        //? extends T
//        list1 = list3; //编译不通过
        list1 = list4;
//        list1 = list5;

        //写入:不允许
        list1.add(null);//特例
//        list1.add(new Student());//编译不通过
//        list1.add(new Person());//编译不通过
//        list1.add(new Object());//编译不通过

        //读取:合法
        Person p1 = list1.get(0);
        
		//####################################################
        //? super Person
        list2 = list3;
        list2 = list4;
//        list2 = list5;//编译不通过

        //写入:
        list2.add(null);
        list2.add(new Student());//编译通过
        list2.add(new Person());//编译通过
//        list2.add(new Object());//编译不通过

        //读取:
        Object obj = list2.get(0);
    }

2. 练习题

import java.util.*;

/**
 * 定义个泛型类 DAO<T>,在其中定义一个Map 成员变量,Map 的键为 String 类型,值为 T 类型。
 * <p>
 * 分别创建以下方法:
 * public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中
 * public T get(String id):从 map 中获取 id 对应的对象
 * public void update(String id,T entity):替换 map 中key为id的内容,改为 entity 对象
 * public List<T> list():返回 map 中存放的所有 T 对象
 * public void delete(String id):删除指定 id 对象
 *
 */
public class DAO<T> {
    private Map<String, T> map;
    public DAO(){
        map = new HashMap<>();
    }
    //保存 T 类型的对象到 Map 成员变量中
    public void save(String id, T entity) {
        if(!map.containsKey(id)){
            map.put(id,entity);
        }
    }

    public T get(String id) {
        return map.get(id);
    }
    //替换 map 中key为id的内容,改为 entity 对象
    public void update(String id, T entity) {
        if(map.containsKey(id)){
            map.put(id,entity);
        }
    }
    //返回 map 中存放的所有 T 对象
    public List<T> list() {
        Collection<T> values = map.values();
        //错误的:
//        return (List<T>) values;

        System.out.println(values.getClass());
        //正确的方式1
        ArrayList<T> list = new ArrayList<>(values.size());
        for(T t : values){
            list.add(t);
        }
        return list;

        //正确的方式2
//        ArrayList<T> list = new ArrayList<>(values.size());
//        list.addAll(values);
//        return list;

        //正确的方式3
//        ArrayList<T> list = new ArrayList<T>(values);
//        return list;

    }
    //删除指定 id 对象
    public void delete(String id) {
        map.remove(id);
    }
}
/**
 * 定义一个 User 类:
 * 该类包含:private成员变量(int类型) id,age;(String 类型)name。
 *
 * hashCode() 与 equals()保持一致性!
 *
 */
public class User {
    private int id;
    private int age;
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public User() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (id != user.id) return false;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }
    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}
import java.util.List;

/**
 * 创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,
 * 使用 Junit 单元测试类进行测试。
 *
 */
public class DAOTest {
    public static void main(String[] args) {
        DAO<User> dao = new DAO<User>();

        dao.save("1",new User(1001,32,"周杰伦"));
        dao.save("2",new User(1002,22,"昆凌"));

        dao.update("2",new User(1003,25,"蔡依林"));

        List<User> list = dao.list();
        System.out.println(list);

    }
}

3. File类的使用

/**
 * File类的使用
 *
 * 1. File类及后续的各种流都声明在java.io 包下
 * 2. File类的对象代表一个文件(.java,.mp3,.doc ,.txt,.avi )或文件目录
 * 3. File通常都是作为IO流的端点出现的。从代码上看,将File类的对象作为参数传递到IO流的构造器中。
 * 4. File类中涉及到文件或文件目录的新建、路径名、大小、删除等操作。具体读取文件内容的行为,File
 *   是无能为力的,必须使用流来操作。
 *
 */
public class FileTest {
    /*
    * File类的实例化
    * public File(String pathname)
    *
    * public File(String parent,String child)
        以parent为父路径,child为子路径创建File对象。
    *
    * public File(File parent,String child)
        根据一个父File对象和子文件路径创建File对象

        *文件(或文件目录)的路径
        * 绝对路径:包含盘符在内的文件或文件目录的完整路径。比如:C:\Program Files (x86)\Bonjour\abc.txt
        * 相对路径:通常都是相较于当前工程或当前module
        *
    * */
//    String str = "我是一个\"好\"人";
//    System.out.println(str);
    @Test
    public void test1(){
        //表示文件
        File file1 = new File("hello.txt");
        File file2 = new File("abc/nello.txt");
        //表示文件目录
        File file3 = new File("C:\\Program Files (x86)\\Bonjour");

        //File(String parent,String child)
        File file4 = new File("C:\\Program Files (x86)\\Bonjour","abc.txt");

        //public File(File parent,String child)
        File file5 = new File(file3,"abc.txt");

    }

    /**
     * File类的获取功能
     * public String getAbsolutePath():获取绝对路径
     * public File getAbsoluteFile():获取绝对路径表示的文件
     * public String getPath() :获取路径
     * public String getName() :获取名称
     * public String getParent():获取上层文件目录路径。若无,返回null
     * public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
     * public long lastModified() :获取最后一次的修改时间,毫秒值
     *
     */

    @Test
    public void test2(){
        File file1 = new File("hello.txt");
        file1 = new File("d:\\io\\hello.txt");
        file1 = new File("d:\\io");
        System.out.println(file1.getAbsolutePath());
        System.out.println(file1.getAbsoluteFile());
        System.out.println(file1.getPath());
        System.out.println(file1.getName());
        System.out.println(file1.getParent());
        System.out.println(file1.length());
        System.out.println(new Date(file1.lastModified()));

        System.out.println(file1.getAbsoluteFile().getParent());
    }

    //练习:创建一个与hello.txt文件在相同文件目录下的另一个名为abc.txt文件
    @Test
    public void test3(){
        File file1 = new File("hello.txt");

        //File(String parent,String child)
        File dest = new File(file1.getAbsoluteFile().getParent(),"abc.txt");
    }

   /* public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
     * public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
    */
   @Test
   public void test4(){
       File file1 = new File("D:\\code210301");
       File[] files = file1.listFiles();
       for(File f : files){
           System.out.println(f);
       }
   }
   /*
   * public boolean isDirectory():判断是否是文件目录
    public boolean isFile() :判断是否是文件
    public boolean exists() :判断是否存在
    public boolean canRead() :判断是否可读
    public boolean canWrite() :判断是否可写
    public boolean isHidden() :判断是否隐藏

   * */
   @Test
   public void test5(){
       File file1 = new File("D:\\code210301");
       file1 = new File("d:\\io\\hello.txt");
       System.out.println(file1.isDirectory());
       System.out.println(file1.isFile());
       System.out.println(file1.exists());//磁盘中是否存在此文件或文件目录
       System.out.println(file1.canRead());
       System.out.println(file1.canWrite());
       System.out.println(file1.isHidden());
   }

   //思考:如何遍历一个文件目录下的所有的文件
    @Test
    public void test6(){
        File file = new File("D:\\code210301");
        printFileName(file);
    }
    public void printFileName(File file){
        if(file.isFile()){
            System.out.println(file.getAbsolutePath());
        }else{
            File[] files = file.listFiles();
            for(File f : files){
                printFileName(f);
            }
        }
    }

    //思考1:获取指定文件目录的大小
    //思考2:删除指定的文件目录

    /*
     *  public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
        public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
        public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
     *  public boolean delete():删除文件或者文件夹
    **/
    @Test
    public void test7() throws IOException {
        File file1 = new File("d:\\io\\abc.txt");

        if(!file1.exists()){//若文件不存在
            System.out.println(file1.createNewFile()? "创建成功" : "创建失败");
        }else{//若文件存在
            System.out.println(file1.delete()? "删除成功":"删除失败");
        }
    }

    @Test
    public void test8(){
        //mkdir():如果要创建的文件目录已存在,则创建失败。
        //        如果要创建的文件目录的上层目录不存在,则创建失败。
        File file1 = new File("d:\\io\\io2\\io3");

//        System.out.println(file1.mkdir()? "创建成功" : "创建失败");
        //mkdirs():如果要创建的文件目录的上层目录不存在,则一并创建
        //         如果要创建的文件目录已存在,则创建失败。
        System.out.println(file1.mkdirs()? "创建成功" : "创建失败");

        file1.delete();
    }
}
  • 对应的思考题的答案
/**
 * 3. 遍历指定目录所有文件名称,包括子文件目录中的文件。
	拓展1:并计算指定目录占用空间的大小
	拓展2:删除指定文件目录及其下的所有文件
 *
 */
public class ListFilesTest {

	public static void main(String[] args) {
		// 递归:文件目录
		/** 打印出指定目录所有文件名称,包括子文件目录中的文件 */

		// 1.创建目录对象
		File dir = new File("E:\\teach\\01_javaSE\\_尚硅谷Java编程语言\\3_软件");

		// 2.打印目录的子文件
		printSubFile(dir);
	}

	public static void printSubFile(File dir) {
		// 打印目录的子文件
		File[] subfiles = dir.listFiles();

		for (File f : subfiles) {
			if (f.isDirectory()) {// 文件目录
				printSubFile(f);
			} else {// 文件
				System.out.println(f.getAbsolutePath());
			}
		}
	}

	// 方式二:循环实现
	// 列出file目录的下级内容,仅列出一级的话
	// 使用File类的String[] list()比较简单
	public void listSubFiles(File file) {
		if (file.isDirectory()) {
			String[] all = file.list();
			for (String s : all) {
				System.out.println(s);
			}
		} else {
			System.out.println(file + "是文件!");
		}
	}

	// 列出file目录的下级,如果它的下级还是目录,接着列出下级的下级,依次类推
	// 建议使用File类的File[] listFiles()
	public void listAllSubFiles(File file) {
		if (file.isFile()) {
			System.out.println(file);
		} else {
			File[] all = file.listFiles();
			// 如果all[i]是文件,直接打印
			// 如果all[i]是目录,接着再获取它的下一级
			for (File f : all) {
				listAllSubFiles(f);// 递归调用:自己调用自己就叫递归
			}
		}
	}

	// 拓展1:求指定目录所在空间的大小
	// 求任意一个目录的总大小
	public long getDirectorySize(File file) {
		// file是文件,那么直接返回file.length()
		// file是目录,把它的下一级的所有大小加起来就是它的总大小
		long size = 0;
		if (file.isFile()) {
			size += file.length();
		} else {
			File[] all = file.listFiles();// 获取file的下一级
			// 累加all[i]的大小
			for (File f : all) {
				size += getDirectorySize(f);// f的大小;
			}
		}
		return size;
	}

	// 拓展2:删除指定的目录
	public void deleteDirectory(File file) {
		// 如果file是文件,直接delete
		// 如果file是目录,先把它的下一级干掉,然后删除自己
		if (file.isDirectory()) {
			File[] all = file.listFiles();
			// 循环删除的是file的下一级
			for (File f : all) {// f代表file的每一个下级
				deleteDirectory(f);
			}
		}
		// 删除自己
		file.delete();
	}
}

4. IO的概述

  • 流的分类
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)  
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流,处理流

在这里插入图片描述

  • 4个流的抽象基类

在这里插入图片描述

  • 具体的子类 (深色的为重点)
    在这里插入图片描述

5. FileReader/FileWriter

import org.junit.Test;

import java.io.*;

public class FileReaderWriterTest {
    /*
    使用单元测试方法的话,相对路径指的是当前module
    使用main的话,相对路径指的是当前工程
     */
    @Test
    public void test1() throws IOException {
        //1. 创建流(包含了创建文件)
        FileReader fr = new FileReader(new File("hello.txt"));

        //2. 具体的读取操作
        //read():读取下一个字符,并返回。如果到达文件末尾,返回-1.
        int data = fr.read();
        while(data != -1){ //判断是否达到文件末尾
            System.out.print((char)data);
            data = fr.read();
        }

        //3. 关闭资源。一旦缺少关闭操作,就会出现内存泄漏
        fr.close();
    }

    //升级操作:本章中凡是出现流资源的关闭操作,都需要使用try-catch-finally来处理。不能使用throws.
    @Test
    public void test2(){
        FileReader fr = null;
        try{
            //1. 创建流(包含了创建文件)
            fr = new FileReader(new File("hello.txt"));

            //2. 具体的读取操作
            int data = fr.read();
            while(data != -1){ //判断是否达到文件末尾
                System.out.print((char)data);
                data = fr.read();
            }
        }catch(IOException e){
            e.printStackTrace();
        }finally{

            //3. 关闭资源。一旦缺少关闭操作,就会出现内存泄漏
            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //继续升级操作:每次读取数据使用一个数组。效率更高!
    @Test
    public void test3(){
        FileReader fr = null;
        try{
            //1. 创建流(包含了创建文件)
            fr = new FileReader(new File("hello.txt"));

            //2. 具体的读取操作
            char[] cbuffer = new char[5];
            int len;//记录每次读入到cbuffer数组中的字符的个数
            //read(char[] cbuf): 将数据读入到cbuf数组中,并返回读入到此数组中的个数。
            while((len = fr.read(cbuffer)) != -1){ //判断是否达到文件末尾

                //遍历cbuffer数组
                //错误的
//                for(int i = 0;i < cbuffer.length;i++){
//                    System.out.print(cbuffer[i]);
//                }
                //正确的:
//                for(int i = 0;i < len;i++){
//                    System.out.print(cbuffer[i]);
//                }
                //正确的:
                String str = new String(cbuffer,0,len);
                System.out.print(str);

//                Thread.sleep(3000);
            }
        }catch(IOException e){
            e.printStackTrace();
        }finally{

            //3. 关闭资源。一旦缺少关闭操作,就会出现内存泄漏
            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test4() {
        FileWriter fw = null;
        try {
            //1. 创建流(包含输出的文件的创建)
//            fw = new FileWriter(new File("abc.txt"));
            fw = new FileWriter(new File("abc.txt")t);

            //2. 写出数据
            fw.write("I love you!\n");
            fw.write("you love him!".toCharArray());
            fw.write("\n我很痛苦!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭资源
            try {
                if(fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    * 小结:
    *
    * 1. FileReader \FileWriter因为涉及资源的关闭操作,所以有异常的话,必须使用try-catch-finally处理
    * 2. 输入流在读取文件中的数据时,要求此文件必须存在。否则会报FileNotFoundException
    * 3. 输出流在写出数据到指定文件时,写出的文件可以不存在。
    *     3.1 如果写出的文件确实不存在,在执行的过程中,会自动的创建此文件。
    *     3.2 如果写出的文件存在,使用FileWriter(File) 或 FileWriter(File,false)构造器时,在执行的过程中,会覆盖原有文件
    *                         使用FileWriter(File,true)构造器时,在执行的过程中,在原有文件的末尾添加新的数据
    *
    * */

    //实现文本文件的复制
    @Test
    public void test5(){
        FileReader fr = null;
        FileWriter fw = null;
        try {
            //1. 创建流(包含文件的创建)
            fr = new FileReader(new File("hello.txt"));
            fw = new FileWriter(new File("hello_copy.txt"));

            //不能处理非文本文件
//            fr = new FileReader(new File("pony.jpg"));
//            fw = new FileWriter(new File("pony_copy.jpg"));


            //2. 数据的读取和写出
            char[] cbuf = new char[5];
            int len;//记录每次读入到cbuf[]中字符的个数
            while((len = fr.read(cbuf)) != -1){
                //操作1:
                fw.write(cbuf,0,len);
                //操作2:
//                String str = new String(cbuf,0,len).toUpperCase();
//                fw.write(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭流
            //方式1:
//            try {
//                if(fw != null)
//                    fw.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }finally{
//
//                try {
//                    if(fr != null)
//                        fr.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
            //方式2:
            try {
                if(fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

6. FileInputStream / FileOutputStream

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 测试FileInputStream 和 FileOutputStream的使用
 *
 * 小结:
 * 我们使用字符流来处理文本文件(.txt,.java,.py,....)
 *
 * 使用字节流来处理非文本文件(.doc , .mp3, .avi,.jpg,...)
 *  补充:字节流也可以实现文本文件的复制。
 *
 */
public class FileInputOutputStreamTest {

    //实现图片的复制
    @Test
    public void test1() {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            //1. 创建流(包括创建文件的过程)
            fis = new FileInputStream(new File("pony.jpg"));
            fos = new FileOutputStream(new File("pony_copy.jpg"));

//            fis = new FileInputStream(new File("hello.txt"));
//            fos = new FileOutputStream(new File("hello_copy1.txt"));

            //2. 读取数据并写出数据
            byte[] buffer = new byte[10];
            int len;//记录每次读入到buffer[]中的字节的个数
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭资源
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

7. 缓冲流

import com.sun.media.sound.SoftTuning;
import org.junit.Test;

import java.io.*;

/**
 * 缓冲流的使用:提高数据的读写效率
 *
 */
public class BufferedTest {

    //应该使用try-catch-finally处理异常。
    @Test
    public void test1() throws IOException {
        //1. 创建流(包括创建文件的过程)
        FileInputStream fis = new FileInputStream(new File("pony.jpg"));
        FileOutputStream fos = new FileOutputStream(new File("pony_copy.jpg"));

        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        //2. 读取数据并写出数据
        byte[] buffer = new byte[10];
        int len;//记录每次读入到buffer[]中的字节的个数
        while ((len = bis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        System.out.println("复制成功");

        //3. 关闭资源
        //如果涉及到节点流和处理流了,我们应该先关闭处理流,再关闭节点流。(先关外面的流,再关闭里面的流)
        //外部流的关闭操作,自动会在内部将其内部的流关闭。
        bos.close();
        bis.close();

        //省略了
//        fos.close();
//        fis.close();

    }

    //对比FileInputStream 、FileOutputStream 与 BufferedInputStream、BufferedOutputStream的执行效率
    public void copyWithFile(String src,String dest){
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            //1. 创建流(包括创建文件的过程)
            fis = new FileInputStream(new File(src));
            fos = new FileOutputStream(new File(dest));

            //2. 读取数据并写出数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读入到buffer[]中的字节的个数
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭资源
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void copyWithBuffered(String src,String dest){
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //1. 创建流(包括创建文件的过程)
            FileInputStream fis = new FileInputStream(new File(src));
            FileOutputStream fos = new FileOutputStream(new File(dest));

            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            //2. 读取数据并写出数据
            byte[] buffer = new byte[1024];
            int len;//记录每次读入到buffer[]中的字节的个数
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭资源
            try {
                if(bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bis != null)
                    bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test2(){
        long start = System.currentTimeMillis();

        String src = "C:\\Users\\songhk\\Desktop\\考试\\王俊钿\\歌舞.flv";
        String dest = "C:\\Users\\songhk\\Desktop\\考试\\王俊钿\\歌舞2.flv";

//        copyWithFile(src,dest);
        copyWithBuffered(src,dest);

        long end = System.currentTimeMillis();

        System.out.println("花费的总时间为:" + (end - start));//4701 - 937
    }


    //测试BufferedReader和BufferedWriter的使用
    //应该使用try-catch-finally处理异常。
    @Test
    public void test3() throws IOException {

        //1. 造流
        BufferedReader br = new BufferedReader(new FileReader(new File("dbcp.txt")));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));

        //2. 读写过程
        //方式1:
//        char[] cbuf = new char[10];
//        int len;
//        while((len = br.read(cbuf)) != -1){
//            bw.write(cbuf,0,len);
//        }
        //方式2:
        String str;
        while((str = br.readLine()) != null){
            bw.write(str);
//            bw.write("\n");
            bw.newLine();
        }

        //3. 关闭操作
        bw.close();
        br.close();
    }
}

8. 转换流

在这里插入图片描述

import org.junit.Test;

import java.io.*;

/**
 * 测试转换流的使用
 *
 * InputStreamReader: 将输入型的字节流转换为输入型的字符流
 * OutputStreamWriter: 将输出型的字符流转换为输出型的字节流
 *
 *  编码:字符、字符串 ---> 字节 、字节数组,对应着OutputStreamWriter
 *  解码:字节 、字节数组 ---> 字符、字符串 ,对应着InputStreamReader
 *
 *  要想保证解码之后字符没有乱码,必须保证解码使用的字符集与编码使用的字符集相同!
 *
 */
public class InputStreamReaderTest {

    @Test
    public void test1() throws IOException {
        //1.
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("dbcp.txt"));//当前InputStreamReader使用IDEA默认的字符集
        InputStreamReader isr = new InputStreamReader(new FileInputStream("dbcp.txt"),"UTF-8");//当前InputStreamReader显式使用UTF-8字符集
        //2.
        char[] cbuf = new char[10];
        int len;
        while((len = isr.read(cbuf)) != -1){
            String str = new String(cbuf,0,len);
            System.out.print(str);
        }
        //3.
        isr.close();
    }

    @Test
    public void test2() throws IOException {
        //1.
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("dbcp_gbk.txt"),"UTF-8");//会出现乱码
        InputStreamReader isr = new InputStreamReader(new FileInputStream("dbcp_gbk.txt"),"GBK");//不会出现乱码
        //2.
        char[] cbuf = new char[10];
        int len;
        while((len = isr.read(cbuf)) != -1){
            String str = new String(cbuf,0,len);
            System.out.print(str);
        }
        //3.
        isr.close();
    }

    @Test
    public void test3() throws IOException {
        //1.
        InputStreamReader isr = new InputStreamReader(new FileInputStream("dbcp_gbk.txt"),"GBK");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("dbcp_utf8.txt"),"UTF-8");
        //2
        char[] cbuf = new char[10];
        int len;
        while((len = isr.read(cbuf)) != -1){
            osw.write(cbuf,0,len);
        }

        //3.
        osw.close();
        isr.close();
    }
}

对后续知识的启示意义:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值