Java基础知识笔记(三)

 JDK8新特性:Stream流入门、Stream流的创建


什么是Stream?

  • 也叫Stream流,是Jdk8开始新增的一套API (java.util.stream.*),可以用于操作集合或者数组的数据。
  • 优势: Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好。

案例:体验Stream流

需求:

  • 把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合。
package d8_stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 目标:初步体验Stream流的方便与快捷
 */
public class StreamTest1 {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
        System.out.println(names); //[张三丰, 张无忌, 周芷若, 赵敏, 张强]
        // names = [张三丰, 张无忌, 周芷若, 赵敏, 张强]
        //          name

        // 找出姓张,且是3个字的名字,存入到一个新集合中去。
        //方式一:
        //准备一个新的ArrayList集合,存姓张的数据
        List<String> list = new ArrayList<>();
        for (String name : names) {
            //startsWith 以什么开头
            //length 且三个字
            if(name.startsWith("张") && name.length() == 3){
                list.add(name);
            }
        }
        System.out.println(list); //[张三丰, 张无忌]

        //方式二:
        // 开始使用Stream流来解决这个需求。
        //filter  startsWith 过滤出姓张的
        //filter  length 长度字数为 3
        //collect(Collectors.toList()) 收集到 list2 里
        List<String> list2 = names.stream().filter(s -> s.startsWith("张"))
                .filter(a -> a.length()==3).collect(Collectors.toList());
        System.out.println(list2); //[张三丰, 张无忌]
    }
}

Stream流的使用步骤

1、Stream是什么?有什么作用? 结合了什么技术?

  • 简化集合、数组操作的API。结合了Lambda表达式。

2、说说Stream流处理数据的步骤是什么?

  • 先得到集合或者数组的Stream流。
  • 然后调用Stream流的方法对数据进行处理。
  • 获取处理的结果。
     

Stream流的常用方法

1、获取Stream流?

  • 获取 集合 的Stream流

  • 获取 数组 的Stream流

package d8_stream;

import java.util.*;
import java.util.stream.Stream;

/**
 * 目标:掌握Stream流的创建。
 */
public class StreamTest2 {
    public static void main(String[] args) {
        // 1、如何获取List集合的Stream流?
        List<String> names = new ArrayList<> ();
        Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
        Stream<String> stream = names.stream();

        // 2、如何获取Set集合的Stream流?
        Set<String> set = new HashSet<>();
        Collections.addAll(set, "刘德华","张曼玉","蜘蛛精","马德","德玛西亚");
        Stream<String> stream1 = set.stream();
        //forEach 对数据中的结果进行遍历
        stream1.filter(s -> s.contains("德")).forEach(s -> System.out.println(s));
        //马德
        //德玛西亚
        //刘德华

        // 3、如何获取Map集合的Stream流?
        //Map 不可以直接调用Stream方法获得Stream流
        Map<String, Double> map = new HashMap<> ();
        map.put("古力娜扎", 172.3);
        map.put("迪丽热巴", 168.3);
        map.put("马尔扎哈", 166.3);
        map.put("卡尔扎巴", 168.3);

        Set<String> keys = map.keySet();
        //得到Set方法Stream流
        Stream<String> ks = keys.stream();

        Collection<Double> values = map.values();
        Stream<Double> vs = values.stream();

        Set<Map.Entry<String, Double>> entries = map.entrySet();
        Stream<Map.Entry<String, Double>> kvs = entries.stream();
        kvs.filter(e -> e.getKey().contains("巴"))
                .forEach(e -> System.out.println(e.getKey()+ "-->" + e.getValue()));
        //迪丽热巴-->168.3
        //卡尔扎巴-->168.3

        // 4、如何获取数组的Stream流?
        String[] names2 = {"张翠山", "东方不败", "唐大山", "独孤求败"};
        Stream<String> s1 = Arrays.stream(names2);
        Stream<String> s2 = Stream.of(names2);
    }
}


JDK8新特性:Stream的中间方法、终结方法


2、Stream流常见的中间方法

  • 中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。

package d8_stream;

import java.util.Objects;

public class Student {
    private String name;
    private int age;
    private double height;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Double.compare(student.height, height) == 0 && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, height);
    }

    public Student() {
    }

    public Student(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }


    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}
package d8_stream;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

/**
 * 目标:掌握Stream流提供的常见中间方法。
 */
public class StreamTest3 {
    public static void main(String[] args) {
        List<Double> scores = new ArrayList<>();
        Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0);
        // 需求1:找出成绩大于等于60分的数据,并升序后,再输出。
        //filter用来过滤数据,进行筛选 过滤60 60分以上数据 sorted()对剩下的数据默认升序排序 forEach对剩下的数据进行遍历
        scores.stream().filter(s -> s >= 60).sorted().forEach(s -> System.out.println(s));

        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);


        // 需求2:找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出.
        //filter过滤 s代表学生对象 学生年龄23到30
        //(o1, o2) -> o2.getAge() - o1.getAge() 按照年龄降序排序
        // forEach 遍历数据
        students.stream().filter(s -> s.getAge() >= 23 && s.getAge() <= 30)
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .forEach(s -> System.out.println(s));


        // 需求3:取出身高最高的前3名学生,并输出。
        //身高降序排序 选取前三个即可
        //身高为double不能直接做差 用Double.compare
        //limit(3)取出前三个
        //System.out::println 简化代码
        students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
                .limit(3).forEach(System.out::println);
        System.out.println("----------------------------------------------------------------");


        // 需求4:取出身高倒数的2名学生,并输出。   s1 s2 s3 s4 s5 s6
        //身高降序 最后的两个即倒数2名
        //skip 跳过前几个  students.size() - 2 只留下剩下的两个
        students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
                .skip(students.size() - 2).forEach(System.out::println);


        // 需求5:找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出。
        //先找出大于168的学生
        // map 映射
        //Student::getName 把学生对象变成名字 都放进流
        //distinct()用来去重复的
        students.stream().filter(s -> s.getHeight() > 168).map(Student::getName)
                .distinct().forEach(System.out::println);

        // distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode,equals)
        //重写equals 依赖hashCode
        students.stream().filter(s -> s.getHeight() > 168)
                .distinct().forEach(System.out::println);

        //concat
        Stream<String> st1 = Stream.of("张三", "李四");
        Stream<String> st2 = Stream.of("张三2", "李四2", "王五");
        //concat合并 将st1合并st2到一起
        Stream<String> allSt = Stream.concat(st1, st2);
        allSt.forEach(System.out::println);
    }
}

3、Stream流常见的终结方法

  • 终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。

  • 收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回。
  • Stream流:方便操作集合/数组的手段;   集合/数组:才是开发中的目的。

package d8_stream;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 目标:Stream流的终结方法
 */
public class StreamTest4 {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);
        
        // 需求1:请计算出身高超过168的学生有几人
        //s.getHeight() > 168 身高超过168的学生
        // count() 统计数量
        long size = students.stream().filter(s -> s.getHeight() > 168).count();
        System.out.println(size);

        // 需求2:请找出身高最高的学生对象,并输出。
        // 声明max比较规则 (o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())
        //get() 获取身高最高的学生对象
        Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
        System.out.println(s);

        
        // 需求3:请找出身高最矮的学生对象,并输出。
        Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
        System.out.println(ss);

        // 需求4:请找出身高超过170的学生对象,并放到一个新集合中去返回。
        // collect 终结对象
        // 流只能收集一次。
        List<Student> students1 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toList());
        System.out.println(students1);

        //身高超170 放入set集合中
        // 流只能收集一次。
        Set<Student> students2 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toSet());
        System.out.println(students2);

        // 需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。
        
        
        Map<String, Double> map =
                students.stream().filter(a -> a.getHeight() > 170)
                        .distinct().collect(Collectors.toMap(a -> a.getName(), a -> a.getHeight()));
        System.out.println(map);

        // Object[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray();
        Student[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray(len -> new Student[len]);
        System.out.println(Arrays.toString(arr));
    }
}


IO流(一):File、IO流概述、File文件对象的创建


存储数据的方案

有些数据想长久保存起来,咋整?

  • 文件是非常重要的存储方式,在计算机硬盘中。
  • 即便断电,或者程序终止了,存储在硬盘文件中的数据也不会丢失。

File类

  • File是java.io.包下的类, File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。

  • 注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据。
     

IO流

  • 用于读写数据的(可以读写文件,或网络中的数据…)

  • File:代表文本
  • IO流:读写数据

创建File类的对象

package com.liu.d1_file;

import java.io.File;

/**
 * 目标:掌握File创建对象,代表具体文件的方案。
 */
public class FileTest1 {
    public static void main(String[] args) {
        // 1、创建一个File对象,指代某个具体的文件。
        // 路径分隔符 \\ 和 / 都可以
        // File f1 = new File("D:/resource/ab.txt");
        // File f1 = new File("D:\\resource\\ab.txt");//有参构造器,声明文件路径 代表指代某个具体的文件

        //File.separator 是什么系统用什么分隔符
        File f1 = new File("D:" + File.separator +"resource" + File.separator + "ab.txt");

        //打印
        System.out.println(f1.length()); // 文件大小 //f1是一个对象 表示返回文件对象

        //File 可以指向文件夹
        File f2 = new File("D:/resource");
        System.out.println(f2.length()); //取文件夹本身大小

        // 注意:File对象可以指代一个不存在的文件路径
        File f3 = new File("D:/resource/aaaa.txt"); //随便定位一个文件
        System.out.println(f3.length()); //因为文件不存在,则返回大小为0
        //exists() 判断文件路径是否存在
        System.out.println(f3.exists());// false

        // 我现在要定位的文件是在idea的模块中,应该怎么定位呢?
        // 绝对路径:带盘符的
        // File f4 = new File("D:\\code\\javasepromax\\file-io-app\\src\\itheima.txt"); //从idea拿到文件的路径,copy过来(绝对路径)
        // 相对路径(重点)(建议使用):不带盘符,默认是直接去工程下寻找文件的。
        File f4 = new File("file-io-app\\src\\itheima.txt"); //相对路径 
        System.out.println(f4.length());
    }
}

注意

  • File对象既可以代表文件、也可以代表文件夹。
  • File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。

绝对路径、相对路径

  • 绝对路径:从盘符开始

  • 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件。

1、File类构建对象的方式是什么样的?File的对象可以代表哪些东西?

  • File file = new File(“文件/文件夹/绝对路径/相对路径”);

2、绝对路径和相对路径是什么意思?

  • 绝对路径是带盘符的。
  • 相对路径是不带盘符的,默认到当前工程下寻找文件。

IO流(一):File类的常用方法、案例


File提供的判断文件类型、获取文件信息功能

package com.liu.d1_file;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;

/**
 目标:掌握File提供的判断文件类型、获取文件信息功能
 */
public class FileTest2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        // 1.创建文件对象,指代某个文件
        File f1 = new File("D:/resource/ab.txt");
        //File f1 = new File("D:/resource/");

        // 2、public boolean exists():判断当前文件对象,对应的文件路径是否存在,存在返回true.
        //判断ab.txt文件是否存在
        System.out.println(f1.exists());//存在返回true 不存在返回false

        // 3、public boolean isFile() : 判断当前文件对象指代的是否是文件,是文件返回true,反之。
        //判断ab.txt是否是文件
        System.out.println(f1.isFile());

        // 4、public boolean isDirectory()  : 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之。
        // ab.txt 是否为文件夹
        System.out.println(f1.isDirectory()); //不是文件夹 false

        // 5.public String getName():获取文件的名称(包含后缀)
        System.out.println(f1.getName()); //ab.txt //若问文件夹 返回结果还会返回文件夹里面的路径

        // 6.public long length():获取文件的大小,返回字节个数
        System.out.println(f1.length());

        // 7.public long lastModified():获取文件的最后修改时间。
        long time = f1.lastModified();

        //时间毫秒值对应的具体时间
        //yyyy/MM/dd HH:mm:ss 指定格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        //格式化
        System.out.println(sdf.format(time));

        // 8.public String getPath():获取创建文件对象时,使用的路径
        File f2 = new File("D:\\resource\\ab.txt"); //创建一个文件对象(绝对路径)
        File f3 = new File("file-io-app\\src\\itheima.txt"); //创建一个文件路径 (相对路径)
        System.out.println(f2.getPath()); //创建的是什么路径,返回的就是什么路径
        System.out.println(f3.getPath()); //创建的是什么路径,返回的就是什么路径

        // 9.public String getAbsolutePath():获取绝对路径
        System.out.println(f2.getAbsolutePath()); //本来就是绝对路径,返回就是绝对路径
        System.out.println(f3.getAbsolutePath()); //相对路径转为相对路径返回
    }
}

File类创建文件的功能

File类删除文件的功能

  • 注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。

package com.liu.d1_file;

import java.io.File;

/**
 * 目标:掌握File创建和删除文件相关的方法。
 */
public class FileTest3 {
    public static void main(String[] args) throws Exception {

        // 1、public boolean createNewFile():创建一个新文件(文件内容为空),创建成功返回true,反之。
        File f1 = new File("D:/resource/itheima2.txt");
        System.out.println(f1.createNewFile()); //创建成功 返回true

        // 2、public boolean mkdir():用于创建文件夹,注意:只能创建一级文件夹
        //错误写法 D:/resource/bbb/ccc/ddd/eee/fff/ggg
        //只能创建一级文件夹 D:/resource/aaa
        File f2 = new File("D:/resource/aaa");
        System.out.println(f2.mkdir());

        // 3、public boolean mkdirs():用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File("D:/resource/bbb/ccc/ddd/eee/fff/ggg");
        System.out.println(f3.mkdirs());

        // 3、public boolean delete():删除文件,或者空文件,注意:不能删除非空文件夹。
        System.out.println(f1.delete());
        System.out.println(f2.delete());
        File f4 = new File("D:/resource");
        System.out.println(f4.delete());
    }
}

1、创建多级目录使用哪个方法?

  • public boolean mkdirs()

2、删除文件需要注意什么?

  • 可以删除文件、空文件夹。
  • 默认不能删除非空文件夹。

File类提供的遍历文件夹的功能

package com.liu.d1_file;

import java.io.File;
import java.util.Arrays;

/**
 * 目标:掌握File提供的遍历文件夹的方法。
 */
public class FileTest4 {
    public static void main(String[] args) {
        // 1、public String[] list():获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回。
        File f1 = new File("D:\\course\\待研发内容");
        String[] names = f1.list();//定义字符串数组,接收文件名称
        //遍历
        for (String name : names) {
            System.out.println(name);
        }

        // 2、public File[] listFiles():(重点)获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
        File[] files = f1.listFiles();
        //遍历文件对象
        for (File file : files) {
            System.out.println(file.getAbsolutePath()); //取绝对路径
        }

        // 当主调是空文件夹时,返回一个长度为0的数组
        File f = new File("D:/resource/aaa");
        File[] files1 = f.listFiles();
        System.out.println(Arrays.toString(files1));
    }
}

使用listFiles方法时的注意事项:

  • 当主调是文件,或者路径不存在时,返回null
  • 当主调是空文件夹时,返回一个长度为0的数组
  • 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
  • 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

如何遍历文件夹下的文件对象,使用哪个API,有什么特点?

  • File[] listFiles()(常用)。
  • 只能遍历当前文件夹对象下的一级文件对象。

案例:改变某个文件夹下视频的序号,要求从19开始

package com.liu.d1_file;

import java.io.File;

public class Test {
    public static void main(String[] args) {
        //目标:改变某个文件夹下视频的序号,要求从19开始
        File dir = new File("E:\\w\\视频\\day02视频");

        //1、拿到下面全部的视频,一级文件对象
        File[] videos = dir.listFiles();

        //2、一个一个的找
        for (File video:videos){
            //3、拿到它的名字
            String name = video.getName(); //name = "10、多态、继承..."
            String index = name.substring(0, name.indexOf("、"));
            String lastName = name.substring(name.indexOf("、"));
            String newName = (Integer.valueOf(index) + 18) + lastName;
            
            //4、正式改名
            video.renameTo(new File(dir,newName));
        }


    }
}

IO流(一):前置知识:方法递归、递归的算法和执行流程


什么是方法递归?

  • 递归是一种算法,在程序设计语言中广泛应用。
  • 从形式上说:方法调用自身的形式称为方法递归( recursion)。

递归的形式

  • 直接递归:方法自己调用自己。
  • 间接递归:方法调用其他方法,其他方法又回调方法自己。
package com.liu.d2_recursion;

/**
 * 目标:认识一下递归的形式。
 */
public class RecursionTest1 {
    public static void main(String[] args) {
        //主程序调用方法,报错
        test1(); //出错,栈内存溢出
    }

    // 直接方法递归
    //定义 test1方法
    public static void test1(){
        System.out.println("----test1---");
        //方法自己调用自己
        test1(); // 直接方法递归
    }

    // 间接方法递归 
    public static void test2(){
        System.out.println("---test2---");
        test3();
    }

    public static void test3(){
        test2(); // 间接递归
    }
}

使用方法递归时需要注意的问题:

  • 递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。

什么是递归死循环?

  • 方法无限调用自己,无法终止,最终引起栈内存溢出。
     

案例:计算n的阶乘

需求:

计算n的阶乘,5的阶乘=1*2*3*4*5;  6的阶乘=1*2*3*4*5*6;

分析

1、假如我们认为存在一个公式是 f(n) = 1*2*3*4*5*6*7*…(n-1)*n;

2、那么公式等价形式就是: f(n) = f(n-1) *n

3、如果求的是 1-5 的阶乘 的结果,我们手工应该如何应用上述公式计算。
f(5) =  f(4) * 5
f(4) =  f(3) * 4
f(3) =  f(2) * 3
f(2) =  f(1) * 2
f(1) =  1

package com.liu.d2_recursion;

public class RecursionTest2 {
    //目标:掌握递归的应用,执行流程和算法思想
    public static void main(String[] args) {
        System.out.println("5的阶乘是:" + f(5));
    }

    public static int f(int n){
        //终结点
        if (n == 1){
            return 1;
        }else {
            return f(n-1) * n ;
        }
    }
}


案例:递归求阶乘的执行流程

递归算法三要素:

  • 递归的公式: f(n) =  f(n-1) * n;
  • 递归的终结点:f(1) 
  • 递归的方向必须走向终结点:f(5) =  f(4) * 5;f(4) =  f(3) * 4;f(3) =  f(2) * 3;f(2) =  f(1) * 2  f(1) =  1


IO流(一):File文件搜索-啤酒问题-删除非空文件夹


案例:文件搜索

需求:

从D:盘中,搜索“QQ.exe” 这个文件,找到后直接输出其位置。

分析:

1、先找出D:盘下的所有一级文件对象

2、遍历全部一级文件对象,判断是否是文件

3、如果是文件,判断是否是自己想要的

4、如果是文件夹,需要继续进入到该文件夹,重复上述过程
 

package com.liu.d2_recursion;

import java.io.File;

/**
 * 目标:掌握文件搜索的实现。
 */
public class RecursionTest3 {
    public static void main(String[] args) throws Exception {
        //传数据 路径和文件名
        searchFile(new File("D:/") , "QQ.exe");
    }

    /**
     * 去目录下搜索某个文件
     * @param dir  目录
     * @param fileName 要搜索的文件名称
     */
    //设置方法 需要接收参数:file类型参数,取名dir;String类型,要搜索文件的名称 fileName
    // throws Exception 启动文件
    public static void searchFile(File dir, String fileName) throws Exception {
        // 1、把非法的情况都拦截住
        if(dir == null || !dir.exists() || dir.isFile()){
            return; // 代表无法搜索
        }

        // 2、dir不是null,存在,一定是目录对象。
        // 获取当前目录下的全部一级文件对象。
        File[] files = dir.listFiles(); // 返回数组,存放一级文件对象,dir.listFiles()

        // 3、判断当前目录下是否存在一级文件对象,以及是否可以拿到一级文件对象。
        if(files != null && files.length > 0){
            // 4、遍历全部一级文件对象。
            for (File f : files) {
                // 5、判断文件是否是文件,还是文件夹
                if(f.isFile()){
                    // 是文件,判断这个文件名是否是我们要找的
                    if(f.getName().contains(fileName)){ //判断是否包含要查的文件名
                        System.out.println("找到了:" + f.getAbsolutePath());
                        //找到文件之后,启动文件
                        Runtime runtime = Runtime.getRuntime();
                        runtime.exec(f.getAbsolutePath()); //绝对路径
                    }
                }else {
                    // 遍历的是文件夹,调用方法,继续重复这个过程(递归)
                    searchFile(f, fileName);
                }
            }
        }
    }
}

案例:删除非空文件夹

package com.liu.d2_recursion;

import java.io.File;
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        //目标:删除非空文件夹,独立功能独立成方法
        File dir = new File("E:\\resource\\秘密");
        deleteDir(dir);
    }

    public static void deleteDir(File dir) {
        if (dir == null || !dir.exists()) {
            return;
        }

        if (dir.isFile()) {
            dir.delete();
            return;
        }

        //1、dir存在且是文件夹,拿里面的一级文件对象
        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        if (files.length == 0) {
            dir.delete();
            return;
        }

        //2、这是一个有内容的文件夹,干掉里面的内容,再干掉自己
        for (File file : files) {
            if (file.isFile()) {
                file.delete();
            } else {
                deleteDir(file);
            }
        }
        dir.delete();
    }
}

案例:啤酒

package com.liu.d2_recursion;

public class Test1 {
    public static  int totalNumber; //总酒数
    public static  int lastBattleNumber;
    public static  int lastCoverNumber; //总酒数
    public static void main(String[] args) {
        //啤酒问题:啤酒2元一瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶
        // 请问10元可以喝多少瓶
        buy(10);

        System.out.println("总数:" + totalNumber);
        System.out.println("剩余盖子数" + lastCoverNumber);
        System.out.println("剩余瓶子数:" + lastBattleNumber);
    }

    public static void buy(int money){
        //1、先买了再说
        int buyNumber = money / 2;
        totalNumber += buyNumber;

        //2、把盖子和瓶子换算成钱继续买
        //计算本轮总的盖子和瓶子数
        int allBottleNumber = buyNumber + lastBattleNumber;
        int allCoverNumber = buyNumber + lastCoverNumber;

        int allMoney = 0 ;

        if (allBottleNumber >= 2){
            allMoney += (allBottleNumber / 2) * 2;
        }
        lastBattleNumber = allBottleNumber % 2;

        if (allCoverNumber >= 4){
            allMoney += (allCoverNumber / 4) * 2;
        }
        lastCoverNumber = allCoverNumber % 4;

        if (allMoney >= 2){
            buy(allMoney);
        }
    }
}

文件搜索用到了什么技术?

  • 递归,listFile只是搜索到了一级文件对象。

IO流(一):前置知识-字符集、UTF-8、GBK、ASCII、乱码问题、编码和解码等 


标准ASCII字符集

  • ASCII(American Standard Code for Information Interchange): 美国信息交换标准代码,包括了英文、符号等。
  • 标准ASCII使用1个字节存储一个字符,首尾是0,总共可表示128个字符,对美国佬来说完全够用。

GBK(汉字内码扩展规范,国标)

  • 汉字编码字符集,包含了2万多个汉字等字符,GBK中一个中文字符编码成两个字节的形式存储。
  • 注意:GBK兼容了ASCII字符集。

Unicode字符集(统一码,也叫万国码)

  • Unicode是国际组织制定的,可以容纳世界上所有文字、符号的字符集。
     

UTF-8 

  • 是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节
  • 英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节。

  • 注意:技术人员在开发时都应该使用UTF-8编码!

本节要点

  • ASCII字符集:只有英文、数字、符号等,占1个字节。
  • GBK字符集:汉字占2个字节,英文、数字占1个字节。
  • UTF-8字符集:汉字占3个字节,英文、数字占1个字节。

注意: 

  • 注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码
  • 注意2:英文,数字一般不会乱码,因为很多字符集都兼容了ASCII编码。
     

Java代码完成对字符的编码

编码:把字符按照指定字符集编码成字节

Java代码完成对字符的解码

解码:把字节按照指定字符集解码成字符

package com.liu.d3_charset;

import java.util.Arrays;

/**
 * 目标:掌握如何使用Java代码完成对字符的编码和解码。
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 1、编码
        String data = "a我b";
        byte[] bytes = data.getBytes(); // 默认是按照平台字符集(UTF-8)进行编码的。
        //总共5个字节 :--97代表a--  --[97, -26, -120, -111, 98] 代表我--  --98代表b--
        System.out.println(Arrays.toString(bytes)); //[97, -26, -120, -111, 98]

        // 按照指定字符集进行编码。
        byte[] bytes1 = data.getBytes("GBK"); //使用GBK对字符串进行编码
        System.out.println(Arrays.toString(bytes1)); //[97, -50, -46, 98]

        // 2、解码
        String s1 = new String(bytes); // 按照平台默认编码(UTF-8)解码
        System.out.println(s1); //a我b

        String s2 = new String(bytes1, "GBK");
        System.out.println(s2); //a我b
    }
}


如何使用Java程序对字符进行编码?

  • String类下的方法:
  • byte[] getBytes​():默认编码
  • byte[] getBytes​(String charsetName):指定编码

如何使用Java程序对字节进行解码?

  • String类的构造器:
  • String​(byte[] bytes):使用默认编码解码
  • String​(byte[] bytes, String charsetName)):指定编码解码
     

IO(一):IO流概述、字节流-FileInputStream每次读取一个字节


IO流概述

  • 输入输出流 读写数据的

IO流的应用场景

怎么学IO流?

  • 1、先搞清楚IO流的分类、体系。
  • 2、再挨个学习每个IO流的作用、用法。
     

IO流的分类

  • 按流的方向分为:

  • 按流中数据的最小单位,分为:

IO流总体来看就有四大流

总结流的四大类:

  • 字节输入流:以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流
  • 字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流。
  • 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流。
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流。

IO流的体系

1、IO流的作用?

  • 读写文件数据的

2、IO流是怎么划分的,大体分为几类,各自的作用?

  • 字节输入流 InputStream(读字节数据的)
  • 字节输出流 OutoutStream(写字节数据出去的)
  • 字符输入流 Reader(读字符数据的)
  • 字符输出流 Writer(写字符数据出去的)

IO流的体系

FileInputStream(文件字节输入流)

  • 作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。

注意事项:

  • 使用FileInputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。

FileInputStream(文件字节输入流)(每次读取一个字节)

  • 作用:以内存为基准,把文件中的数据以字节的形式读入到内存中去。

package com.liu.d4_byte_stream;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 目标:掌握文件字节输入流,每次读取一个字节。
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception { //throws Exception 抛出异常
        // 1、创建文件字节输入流管道,与源文件接通。
        // file-io-app\\src\\itheima01.txt 该路径文件 就在次此项目工程里的src下新建的文件
        // InputStream is = new FileInputStream(new File("file-io-app\\src\\itheima01.txt"));
        // 简化写法:推荐使用
        InputStream is = new FileInputStream(("file-io-app\\src\\itheima01.txt"));

        // 2、开始读取文件的字节数据。
        // public int read()方法:每次读取一个字节返回,如果没有数据了,返回-1.
//        int b1 = is.read();// 每次从管道读取文件一个字节
//        System.out.println((char)b1); //转字符型
//
//        int b2 = is.read(); //b2代表第二个字节
//        System.out.println((char) b2);
//
//        int b3 = is.read();
//        System.out.println(b3);

        // 3、使用循环改造上述代码
        int b; // 用于记住读取的字节。
        while ((b = is.read()) != -1){
            System.out.print((char) b);
        }

        //方案存在的问题:
        // 读取数据的性能很差!
        // 读取汉字输出会乱码!!无法避免的!!


        // 流使用完毕之后,必须关闭!释放系统资源!
        is.close();
    }
}

FileInputStream(文件字节输入流)(每次读取多个字节)

  • 作用:以内存为基准,把文件中的数据以字节的形式读入到内存中去。

package com.liu.d4_byte_stream;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 目标:掌握使用FileInputStream每次读取多个字节。
 */
public class FileInputStreamTest2 {
    public static void main(String[] args) throws Exception { //throws Exception 抛出异常
       
        // 1、创建一个字节输入流对象代表字节输入流管道与源文件接通。
        InputStream is = new FileInputStream("file-io-app\\src\\itheima02.txt");
        
        
        //  public int read(byte b[]) throws IOException 方法
        //  每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1.

        // 2、开始读取文件中的字节数据:每次读取多个字节。
        //定义字节数组,装多个字节
//        byte[] buffer = new byte[3]; //每次读取3个字节
//        int len = is.read(buffer); //读取字节
//        String rs = new String(buffer); //转字节数组
//        System.out.println(rs); //abc
//        System.out.println("当次读取的字节数量:" + len); //3
//
//        // buffer = [abc]
//        // buffer = [66c]
//        int len2 = is.read(buffer); //第二次读出
//        // 注意:读取多少,倒出多少。
//        String rs2 = new String(buffer, 0, len2); //0代表从第一个字节开始 也就是从6开始
//        System.out.println(rs2); // 66c
//        System.out.println("当次读取的字节数量:" + len2); //2
//

//        int len3 = is.read(buffer); //第三次读出
//        System.out.println(len3); // -1 //无数据,输出-1

        //优化代码 
        // 3、使用循环 进行 改造
        byte[] buffer = new byte[3];
        int len; // 记住每次读取了多少个字节。  abc 66
        while ((len = is.read(buffer)) != -1){  //不等于-1 说明读到字节
            // 注意:读取多少,倒出多少。
            String rs = new String(buffer, 0 , len); 
            System.out.print(rs); //打印不用换行 
        }
        
        //简化后的代码:
        // 性能得到了明显的提升!!
        // 这种方案也不能避免读取汉字输出乱码的问题!!

        is.close(); // 关闭流
    }
}

1、使用字节流读取中文,如何保证输出不乱码,怎么解决?

  • 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。

2、每次读取一个字节数组有什么好处? 存在什么问题?

  • 读取的性能得到了提升
  • 读取中文字符输出无法避免乱码问题。

文件字节输入流:一次读取完全部字节

  • 方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次读完文件的全部字节。

  • 方式二:Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回。

package com.liu.d4_byte_stream;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 目标:使用文件字节输入流一次读取完文件的全部字节。
 */
public class FileInputStreamTest3 {
    public static void main(String[] args) throws Exception { //throws Exception 抛出异常
        // 1、一次性读取完文件的全部字节到一个字节数组中去。
        // 创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");

        //方法一
        // 2、准备一个字节数组,大小与文件的大小正好一样大。
        //用文件对象 指代文件大小
//        File f = new File("file-io-app\\src\\itheima03.txt");
//        long size = f.length(); //返回文件大小
        //定义一共数组     (int) size 此方案适合读取文件大小较小的文件
//        byte[] buffer = new byte[(int) size]; // 从long 强转为int型
//
//        int len = is.read(buffer); //读取字节
//        System.out.println(new String(buffer)); //转为字符串
//
//        System.out.println(size);
//        System.out.println(len);

        //方法二
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));

        is.close(); // 关闭流
    }
}


直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?

  • 如果文件过大,创建的字节数组也会过大,可能引起内存溢出。


IO流(一):字节流-FileOutputStream、字节流完成文件拷贝


IO流的体系

FileOutputStream(文件字节输出流)

  • 作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。

package com.liu.d4_byte_stream;

import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * 目标:掌握文件字节输出流FileOutputStream的使用。
 */
public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception { //throws Exception 抛出异常
        // 1、创建一个字节输出流管道与目标文件接通。
        // 覆盖管道:覆盖之前的数据
//        OutputStream os =
//                new FileOutputStream("file-io-app/src/itheima04out.txt");

        // 追加数据的管道
        //true 不会覆盖之前的数据 继续往后追加
        OutputStream os = new FileOutputStream("file-io-app/src/itheima04out.txt", true); //文件可以自动生成

        // 2、开始写字节数据出去了
        os.write(97); // 97就是一个字节,代表a
        os.write('b'); // 'b'也是一个字节
        // os.write('磊'); // [ooo] 默认只能写出去一个字节

        // getBytes() 把字符串转换成字节数组
        byte[] bytes = "我爱你中国abc".getBytes();
        os.write(bytes);

        os.write(bytes, 0, 15); // 我爱你中国 写出去

        // 换行符 \r\n
        //字节写出去 可以实现换行
        //getBytes() 转成字节数组
        os.write("\r\n".getBytes());

        os.close(); // 关闭流
    }
}

文件复制

字节流非常适合做一切文件的复制操作

  • 任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!
package com.liu.d4_byte_stream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 目标:使用字节流完成对文件的复制操作。
 */
public class CopyTest5 {
    public static void main(String[] args) throws Exception { //throws Exceptio 抛出异常
       //此文件复制 可用于 所有文件复制,只要目标文件是个文本文件 没问题就能复制
        // 需求:复制

        // 1、创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");
        // 2、创建一个字节输出流管道与目标文件接通。
        OutputStream os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");

        // 3、创建一个字节数组,负责转移字节数据。
        byte[] buffer = new byte[1024]; // 1KB. //字节数组越大 性能越好

        // 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
        int len; // 记住每次读取了多少个字节。
        while ((len = is.read(buffer)) != -1){
            os.write(buffer, 0, len); //存多少个就倒出多少个 buffer决定多少个
        }

        //关流
        //先关后创建的
        os.close();
        is.close();
        System.out.println("复制完成!!");
    }
}


IO流(一):释放资源-try-catch-finally、try-catch-resource


try-catch-finally

  • finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止。
package com.liu.d5_resource;

/**
 * 目标:认识try-catch-finally。
 */
public class Test1 {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 2); //5
            // return; // 跳出方法的执行
            // System.exit(0); // 虚拟机
        }catch (Exception e){
            e.printStackTrace();
        } finally { //加了finally 即使有return 最后还是会执行一次
            System.out.println("===finally执行了一次==="); //===finally执行了一次===
        }

        System.out.println(chu(10, 2));
    }

    //写方法 除法
    public static int chu(int a, int b){
        try {
            return a / b; //结果return
        }catch (Exception e){
            e.printStackTrace();
            return -1; // 代表的是出现异常 出现异常的时候不会报错
        }finally {
            // 千万不要在finally中返回数据!
            return 111;
        }
    }
}

  • 作用:一般用于在程序执行完成后进行资源的释放操作(专业级做法)。
package com.liu.d5_resource;

import java.io.*;

/**
 * 目标:掌握释放资源的方式。
 */
public class Test2 {
    public static void main(String[] args)  {

        InputStream is = null;
        OutputStream os = null;
        //ctrl + alt + T 选择 try catch
        try {
            System.out.println(10 / 0);
            // 1、创建一个字节输入流管道与源文件接通
            is = new FileInputStream("file-io-app\\src\\itheima03.txt");
            // 2、创建一个字节输出流管道与目标文件接通。
            os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt");

            System.out.println(10 / 0);

            // 3、创建一个字节数组,负责转移字节数据。
            byte[] buffer = new byte[1024]; // 1KB.
            // 4、从字节输入流中读取字节数据,写出去到字节输出流中。读多少写出去多少。
            int len; // 记住每次读取了多少个字节。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
            System.out.println("复制完成!!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源的操作
            try {
                //可避免空指针异常
                if(os != null) os.close(); //关流
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                //可避免空指针异常
                if(is != null) is.close(); //关流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

JDK 7开始提供了更简单的资源释放方案:try-with-resource

try-with-resource:

  • 该资源使用完毕后,会自动调用其close()方法,完成对资源的释放!
  • () 中只能放置资源,否则报错
  • 什么是资源呢?
  • 资源一般指的是最终实现了AutoCloseable接口。
     
package com.liu.d4_byte_stream;

import java.io.FileInputStream;
import java.io.InputStream;

/**
 * 目标:使用文件字节输入流一次读取完文件的全部字节。
 */
public class FileInputStreamTest3 {
    public static void main(String[] args) throws Exception { //throws Exception 抛出异常
        // 1、一次性读取完文件的全部字节到一个字节数组中去。
        // 创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");

        //方法一
        // 2、准备一个字节数组,大小与文件的大小正好一样大。
        //用文件对象 指代文件大小
//        File f = new File("file-io-app\\src\\itheima03.txt");
//        long size = f.length(); //返回文件大小
        //定义一共数组     (int) size 此方案适合读取文件大小较小的文件
//        byte[] buffer = new byte[(int) size]; // 从long 强转为int型
//
//        int len = is.read(buffer); //读取字节
//        System.out.println(new String(buffer)); //转为字符串
//
//        System.out.println(size);
//        System.out.println(len);

        //方法二
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));

        is.close(); // 关闭流
    }
}

IO 流(二):字符流——FileReader、FileWriter、字符输出流的注意事项


IO流的体系

FileReader(文件字符输入流)

  • 作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。

FileWriter(文件字符输出流)

  • 作用:以内存为基准,把内存中的数据以字符的形式写出到文件中去。

package com.liu.d1_char_stream;

import java.io.FileReader;
import java.io.Reader;

/**
 * 目标:掌握文件字符输入流。
 */
public class FileReaderTest1 {
    public static void main(String[] args)  {
        try (
                // 1、创建一个文件字符输入流管道与源文件接通
                Reader fr = new FileReader("io-app2\\src\\itheima01.txt"); //相对路径
        ){
            // 2、读取文本文件的内容了。

            //方法一
            //每次读取一个字符
//            int c; // 记住每次读取的字符编号。
//            while ((c = fr.read()) != -1){
//                System.out.print((char) c); //强转char 不需要换行
//            }
            // 每次读取一个字符的形式,性能肯定是比较差的。


            //方法二
            // 3、每次读取多个字符。
            char[] buffer = new char[3]; //定义一个数组 一次读取三个字符
            int len; // 记住每次读取了多少个字符。
            while ((len = fr.read(buffer)) != -1){
                // 读取多少倒出多少
                System.out.print(new String(buffer, 0, len));
            }
            // 每次读取多个字符 性能是比较不错的!

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

IO流的体系

FileWriter(文件字符输出流)

  • 作用:以内存为基准,把内存中的数据以字符的形式写出到文件中去。

package com.liu.d1_char_stream;

import java.io.FileWriter;
import java.io.Writer;

/**
 * 目标:掌握文件字符输出流:写字符数据出去
 */
public class FileWriterTest2 {
    public static void main(String[] args) {
        //释放异常
        try (
                // 0、创建一个文件字符输出流管道与目标文件接通。
                // 覆盖管道 之前的数据会丢失
                // Writer fw = new FileWriter("io-app2/src/itheima02out.txt");
                // 追加数据的管道 true 之前的数据不会丢失
                Writer fw = new FileWriter("io-app2/src/itheima02out.txt", true); 
        ){
            // 1、public void write(int c):写一个字符出去
            fw.write('a');
            fw.write(97);
            //fw.write('磊'); // 写一个字符出去
            fw.write("\r\n"); // 换行符

            // 2、public void write(String c)写一个字符串出去
            fw.write("我爱你中国abc");
            fw.write("\r\n"); //换行符

            // 3、public void write(String c ,int pos ,int len):写字符串的一部分出去
            fw.write("我爱你中国abc", 0, 5); //0表示从我开始 ,5代表输出我爱你中国
            fw.write("\r\n"); //换行符

            // 4、public void write(char[] buffer):写一个字符数组出去
            char[] buffer = {'黑', '马', 'a', 'b', 'c'};
            fw.write(buffer);
            fw.write("\r\n"); //换行符

            // 5、public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
            fw.write(buffer, 0, 2); // 黑马 
            fw.write("\r\n"); //换行符
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字符输出流使用时的注意事项

  • 字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
     
package com.liu.d1_char_stream;

import java.io.FileWriter;
import java.io.Writer;

/**
 * 目标:搞清楚字符输出流使用时的注意事项。
 */
public class FileWriterTest3 {
    public static void main(String[] args) throws Exception {

        Writer fw = new FileWriter("io-app2/src/itheima03out.txt");

        // 写字符数据出去
        fw.write('a');
        fw.write('b');
        fw.write('c');
        fw.write('d');
        fw.write("\r\n");

        fw.write("我爱你中国");
        fw.write("\r\n");
        fw.write("我爱你中国");

//        fw.flush(); // 刷新流。 //把缓冲区里的内容同步到文件中去
//        fw.write("张三");
//        fw.flush();

        fw.close(); // 关闭流,关闭流包含刷新操作! 自动把缓冲区的数据同步
        // fw.write("张三"); //关闭流后 就不能再写数据
    }
}

字节流、字符流的使用场景小结:

  • 字节流适合做一切文件数据的拷贝(音视频,文本);字节流不适合读取中文内容输出。
  • 字符流适合做文本文件的操作(读,写)。


IO流(二):缓冲流——BufferedReader、BufferedWriter、案例


IO流的体系

字节缓冲流的作用

  • 提高字节流读写数据的性能

原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池。

package com.liu.d2_buffered_stream;

import java.io.*;

/**
 * 目标:掌握字节缓冲流的作用。
 */
public class BufferedInputStreamTest1 {
    public static void main(String[] args) {
        try (
                InputStream is = new FileInputStream("io-app2/src/itheima01.txt");
                // 1、定义一个字节缓冲输入流包装原始的字节输入流
                InputStream bis = new BufferedInputStream(is);

                OutputStream os = new FileOutputStream("io-app2/src/itheima01_bak.txt");
                // 2、定义一个字节缓冲输出流包装原始的字节输出流
                OutputStream bos = new BufferedOutputStream(os);
        ){

            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0, len); 
            }
            System.out.println("复制完成!!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1、缓冲流有几种?

  • 字节缓冲输入流: BufferedInputStream
  • 字节缓冲输出流:BufferedOutputStream
  • 字符缓冲输入流:BufferedReader
  • 字符缓冲输出流:BufferedWriter

2、字节缓冲流为什么提高了字节流读写数据的性能?

  • 字节缓冲流自带8KB缓冲区
  • 可以提高原始字节流、字符流读写数据的性能

3、字节缓冲流如何使用?

  • public BufferedOutputStream​(OutputStream os)
  • public BufferedInputStream​(InputStream is)
  • 功能上并无很大变化,性能提升了。

IO流的体系

BufferedReader(字符缓冲输入流)

  • 作用:自带8K(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能。
     

字符缓冲输入流新增的功能:按照行读取字符
 

package com.liu.d2_buffered_stream;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;

/**
 * 目标:掌握字符缓冲输入流的用法。
 */
public class BufferedReaderTest2 {
    public static void main(String[] args)  {
        try (
                Reader fr = new FileReader("io-app2\\src\\itheima04.txt");
                // 创建一个字符缓冲输入流 包装原始的字符输入流
                //不用多态写 也不用原始得字符输入流
                BufferedReader br = new BufferedReader(fr);
        ){
//            char[] buffer = new char[3];
//            int len;
//            while ((len = br.read(buffer)) != -1){ //br.read(buffer) 读取数据
//                System.out.print(new String(buffer, 0, len));
//            }

            //读取四行 
            //如果下面没用内容 却还在读 就返回null
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());
//            System.out.println(br.readLine());

            //读取文本内容并输出
            String line; // 记住每次读取的一行数据
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

BufferedWriter(字符缓冲输出流)

  • 作用:自带8K的字符缓冲池,可以提高字符输出流写字符数据的性能。
     

字符缓冲输出流新增的功能:换行

package com.liu.d2_buffered_stream;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.Writer;

/**
 * 目标:掌握字符缓冲输出流的用法。
 */
public class BufferedWriterTest3 {
    public static void main(String[] args) {
        try (
                Writer fw = new FileWriter("io-app2/src/itheima05out.txt", true);
                // 创建一个字符缓冲输出流管道包装原始的字符输出流
                //不用多态写
                BufferedWriter bw = new BufferedWriter(fw); 
                //BufferedWriter 默认字符缓冲输出流
        ){

            //用bw 来写
            bw.write('a');
            bw.write(97);
            bw.write('磊');
            bw.newLine();

            bw.write("我爱你中国abc");
            //增加换行功能
            bw.newLine();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1、字符缓冲流有几种,作用是什么?

字符缓冲流自带8K缓冲区

可以提高原始字符流读写数据的性能

2、两种字符缓冲流如何使用?各自新增了什么功能?

  • public BufferedReader​(Reader r)  性能提升了,多了readLine()按照行读取的功能
  • public BufferedWriter​(Writer w)  性能提升了,多了newLine()换行的功能

案例:拷贝出师表到另一个文件,恢复顺序

需求:

  • 把《出师表》的文章顺序进行恢复到一个新文件中。

分析:

  • 1、定义一个缓存字符输入流管道与源文件接通。
  • 2、定义一个List集合存储读取的每行数据。
  • 3、定义一个循环按照行读取数据,存入到List集合中去。
  • 4、对List集合中的每行数据按照首字符编号升序排序。
  • 5、定义一个缓存字符输出管道与目标文件接通。
  • 6、遍历List集合中的每个元素,用缓冲输出管道写出并换行。
package com.liu.d2_buffered_stream;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Test3 {
    public static void main(String[] args) {
      try(
              //2、创建缓冲字符输入流管道与源文件接通、
              BufferedReader br = new BufferedReader(new FileReader("day09-io2\\src\\csd.txt"));
              BufferedWriter bw = new BufferedWriter(new FileWriter("day09-io2\\src\\newcsd.txt"));
          ) {
          //目标:恢复出师表得顺序到新文件中
          //1、定义一个ArrayList集合存储每段内容
          List<String> data = new ArrayList<>();

          //3、按照行读取每段
          String line;
          while ((line = br.readLine()) != null){
              data.add(line);
          }

          //4、对List集合中的每段文章进行排序
          Collections.sort(data);

          //5、遍历List集合的每段内容,依次写出去到新文件中
          for (String ln : data){
              bw.write(ln);
              bw.newLine();

          }

      }catch (Exception e){
          e.printStackTrace();
      }
    }
}


IO流(二):原始流、缓冲流的性能分析


步骤:原始流、缓冲流的性能分析[重点]

测试用例:

  • 分别使用原始的字节流,以及字节缓冲流复制一个很大视频。

测试步骤:

1、使用低级的字节流按照一个一个字节的形式复制文件。、

2、使用低级的字节流按照字节数组的形式复制文件。

3、使用高级的缓冲字节流按照一个一个字节的形式复制文件。

4、使用高级的缓冲字节流按照字节数组的形式复制文件。

package com.liu.d2_buffered_stream;

import java.io.*;

/**
 目标:观察原始流和缓冲流的性能。
 */
public class TimeTest4 {
    // 复制的视频路径
    private static final String SRC_FILE = "D:\\resource\\线程池.avi"; //视频内存889MB
    // 复制到哪个目的地
    private static final String DEST_FILE = "D:\\";

    public static void main(String[] args) {
        //分别调用方法
        // copy01(); // 低级字节流一个一个字节的赋值,慢的简直让人无法忍受,直接淘汰!
        copy02();// 低级的字节流流按照一个一个字节数组的形式复制,速度较慢!
        // copy03(); // 缓冲流按照一个一个字节的形式复制,速度较慢,直接淘汰!
        copy04(); // 缓冲流按照一个一个字节数组的形式复制,速度极快,推荐使用!
    }

    //低级字节流 一个一个字节的赋值
    private static void copy01() {
        //拿到系统的当前时间
        long startTime = System.currentTimeMillis();
        try (
                //原始字节输入流;SRC_FILE复制到1.avi文件里 ; DEST_FILE表示路径重写
                InputStream is = new FileInputStream(SRC_FILE);
                //原始字节输出流
                OutputStream os = new FileOutputStream(DEST_FILE + "1.avi");
        ){
            int b; //记住一个字节
            while ((b = is.read()) != -1){
                os.write(b);
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        //截止时间
        long endTime = System.currentTimeMillis();
        System.out.println("低级字节流一个一个字节复制耗时:" + (endTime - startTime) / 1000.0 + "s");
    }

    // 低级字节流 一个一个字节的赋值
    private static void copy02() {
        long startTime = System.currentTimeMillis();
        try (
                InputStream is = new FileInputStream(SRC_FILE);
                OutputStream os = new FileOutputStream(DEST_FILE + "2.avi");
        ){
            byte[] buffer = new byte[1024*64];
            int len;
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("低级字节流使用字节数组复制耗时:" + (endTime - startTime) / 1000.0 + "s");
    }

    //缓冲流 按照一个一个字节的形式
    private static void copy03() {
        long startTime = System.currentTimeMillis();
        try (
                InputStream is = new FileInputStream(SRC_FILE);
                BufferedInputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream(DEST_FILE + "3.avi"); //拷贝到第三个视频文件中去
                BufferedOutputStream bos = new BufferedOutputStream(os); //缓冲字节输出流
        ){

            int b;
            while ((b = bis.read()) != -1){
                bos.write(b);
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流一个一个字节复制耗时:" + (endTime - startTime) / 1000.0 + "s");
    }


    //缓冲流 按照一个一个字节数组的形式
    private static void copy04() {
        long startTime = System.currentTimeMillis();
        try (
                InputStream is = new FileInputStream(SRC_FILE);
                BufferedInputStream bis = new BufferedInputStream(is, 64 * 1024);
                OutputStream os = new FileOutputStream(DEST_FILE + "4.avi");
                BufferedOutputStream bos = new BufferedOutputStream(os, 64 * 1024);
        ){
            byte[] buffer = new byte[1024 * 64]; // 32KB //字节数组越大越好 读写性能提升 但大到一定程度,性能就不影响
            int len;
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0, len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("缓冲流使用字节数组复制耗时:" + (endTime - startTime) / 1000.0 + "s");
    }
}


推荐使用哪种方式提高字节流读写数据的性能?

建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式,目前来看是性能最优的组合。


IO流(二):引出问题:不同编码读取会出现乱码


不同编码读取出现出现乱码的问题

  • 如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
  • 如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
package com.liu.d3_transform;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;

/**
 * 目标:掌握不同编码读取乱码的问题。
 */
public class Test1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个文件字符输入流与源文件接通
                // 代码编码:UTF-8  文件的编码:UTF-8
                // Reader fr = new FileReader("io-app2/src/itheima04.txt");

                //         1   床     前    明   月光c
                //  GBK    o  [oo]  [oo]  [oo] ...
                //  UTF-8  1 ?????
                // 代码编码:UTF-8 文件的编码:GBK
                Reader fr = new FileReader("io-app2/src/itheima06.txt");
                // 2、把文件字符输入流包装成缓冲字符输入流
                BufferedReader br = new BufferedReader(fr);
        ){
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

IO流(二):转换流——InputStreamReader、OutputStreamWriter


IO流的体系

InputStreamReader(字符输入转换流)

  • 解决不同编码时,字符流读取文本内容乱码的问题。
  • 解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。

package com.liu.d3_transform;

import java.io.*;

/**
 * 目标:掌握字符输入转换流的作用。
 */
public class InputStreamReaderTest2 {
    public static void main(String[] args) {
        try (
                // 1、得到文件的原始字节流(GBK的字节流形式)
                InputStream is = new FileInputStream("io-app2/src/itheima06.txt");
                // 2、把原始的字节输入流按照指定的字符集编码转换成字符输入流
                Reader isr = new InputStreamReader(is, "GBK");
                // 3、把 字符输入流 包装成 缓冲字符输入流
                BufferedReader br = new BufferedReader(isr);
        ){
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字符输入转换流InputStreamReader的作用是啥?

  • 可以解决字符流读取不同编码乱码的问题
  • public InputStreamReader(InputStream is,String charset):   可以指定编码把原始字节流转换成字符流,如此字符流中的字符不乱码。

需要控制写出去的字符 使用什么字符集编码,该咋整?

1、调用String提供的getBytes方法解决? 


2、使用”字符输出转换流”实现。

IO流的体系

OutputStreamWriter字符输出转换流

  • 作用:可以控制写出去的字符使用什么字符集编码。 
  • 解决思路:获取字节输出流,再按照指定的字符集编码将其转换成字符输出流,以后写出去的字符就会用该字符集编码了。

package com.liu.d3_transform;

import java.io.*;

/**
 * 目标:掌握字符输出转换流的使用。
 */
public class OutputStreamWriterTest3 {
    public static void main(String[] args) {
        // 指定写出去的字符编码。
        try (
                // 1、创建一个文件字节输出流
                OutputStream os = new FileOutputStream("io-app2/src/itheima07out.txt");
                // 2、把原始的字节输出流,按照指定的字符集编码转换成字符输出转换流。
                Writer osw = new OutputStreamWriter(os, "GBK");
                // 3、把字符输出流包装成缓冲字符输出流
                BufferedWriter bw = new BufferedWriter(osw);
        ){
            bw.write("我是中国人abc");
            bw.write("我爱你中国123");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


字符输出转换流Output StreamWriter的作用?

public Output StreamWriter(Output Stream os,String charset)
可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码!


IO流(二):其他流:打印流、打印流应用


IO流的体系

PrintStream/PrintWriter(打印流)

  • 作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去。
     

PrintStream提供的打印数据的方案

PrintWriter 提供的打印数据的方案

package com.liu.d4_printstream;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;

/**
 * 目标:掌握打印流:PrintStream/PrintWriter的用法。
 */
public class PrintTest1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个打印流管道
                // PrintStream 打印数据
                //Charset.forName("GBK") 指定字符集对象为GBK
//                PrintStream ps = new PrintStream("io-app2/src/itheima08.txt", Charset.forName("GBK"));
//
//                PrintStream ps = new PrintStream("io-app2/src/itheima08.txt");

                // PrintWriter 打印数据
                //new FileOutputStream  true 追加数据
                PrintWriter ps =
                        new PrintWriter(new FileOutputStream("io-app2/src/itheima08.txt", true));
        ){
            //支持 几乎打印任意类型的数据
            ps.println(97);
            ps.println('a');
            ps.println("我爱你中国abc");
            ps.println(true);
            ps.println(99.5);

            // ps.write(97); // 'a'

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PrintStream和PrintWriter的区别

  • 打印数据的功能上是一模一样的:都是使用方便,性能高效(核心优势)
  • PrintStream继承自字节输出流Output Stream,因此支持写字节数据的方法。
  • PrintWriter继承自字符输出流Writer,因此支持写字符数据出去。

打印功能2者是一样的使用方式

  • PrintStream继承自字节输出流Output Stream,支持写字节
  • PrintWrite继承自字符输出流Writer,支持写字符

打印流的优势是什么?

  • 两者在打印功能上都是使用方便,性能高效(核心优势)

打印流的一种应用:输出语句的重定向

package com.liu.d4_printstream;

import java.io.PrintStream;

/**
 * 目标:了解下输出语句的重定向。
 */
public class PrintTest2 {
    public static void main(String[] args) {
        System.out.println("老骥伏枥"); //内容输入到控制台里
        System.out.println("志在千里");

        try (
                //打印流
                PrintStream ps = new PrintStream("io-app2/src/itheima09.txt"); ){

            // 把系统默认的打印流对象改成自己设置的打印流
            System.setOut(ps);
            //打印的东西 到 itheima09.txt文件 里
            System.out.println("烈士暮年");
            System.out.println("壮心不已");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


IO流(二):其他流:数据流、序列化流


IO流的体系

DataOutputStream(数据输出流)

  • 允许把数据和其类型一并写出去。

package com.liu.d5_data_stream;

import java.io.DataOutputStream;
import java.io.FileOutputStream;

/**
 * 目标:数据输出流。
 */
public class DataOutputStreamTest1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个数据输出流包装低级的字节输出流
                DataOutputStream dos =
                        new DataOutputStream(new FileOutputStream("io-app2/src/itheima10out.txt"));
        ){
            dos.writeInt(97);
            dos.writeDouble(99.5);
            dos.writeBoolean(true);
            dos.writeUTF("黑马程序员666!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DataInputStream(数据输入流)

  • 用于读取数据输出流写出去的数据。 

package com.liu.d5_data_stream;

import java.io.DataInputStream;
import java.io.FileInputStream;

/**
 * 目标:使用数据输入流读取特定类型的数据。
 */
public class DataInputStreamTest2 {
    public static void main(String[] args) {
        try (
                DataInputStream dis =
                        new DataInputStream(new FileInputStream("io-app2/src/itheima10out.txt"));
        ){
            int i = dis.readInt();
            System.out.println(i);

            double d = dis.readDouble();
            System.out.println(d);

            boolean b = dis.readBoolean();
            System.out.println(b);

            String rs = dis.readUTF();
            System.out.println(rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

IO流的体系

ObjectOutputStream(对象字节输出流)

  • 可以把Java对象进行序列化:把Java对象存入到文件中去。

注意:

对象如果要参与序列化,必须实现序列化接口(java.io.Serializable)

package com.liu.d6_object_stream;

import java.io.Serializable; // 注意:对象如果需要序列化,必须实现序列化接口。
public class User implements Serializable {
    private String loginName; //登录名
    private String userName; //用户名
    private int age; //年龄
    // transient 这个成员变量将不参与序列化。
    private transient String passWord;

    public User() {
    }

    public User(String loginName, String userName, int age, String passWord) {
        this.loginName = loginName;
        this.userName = userName;
        this.age = age;
        this.passWord = passWord;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

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

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    @Override
    public String toString() {
        return "User{" +
                "loginName='" + loginName + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", passWord='" + passWord + '\'' +
                '}';
    }
}


package com.liu.d6_object_stream;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/**
 * 目标:掌握对象字节输出流的使用:序列化对象。
 */
public class Test1ObjectOutputStream {
    public static void main(String[] args) {
        try (
                // 2、创建一个对象字节输出流包装原始的字节 输出流。
                ObjectOutputStream oos =
                        new ObjectOutputStream(new FileOutputStream("io-app2/src/itheima11out.txt"));
        ){
            // 1、创建一个Java对象。
            //如果需要 某个对象去进行序列化 必须让对象类去实现一个接口,否则会报错+
            User u = new User("admin", "张三", 32, "666888xyz");

            // 3、序列化对象到文件中去
            oos.writeObject(u);
            System.out.println("序列化对象成功!!");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ObjectInputStream(对象字节输入流)

  • 可以把Java对象进行反序列化:把存储在文件中的Java对象读入到内存中来。

package com.liu.d6_object_stream;

import java.io.Serializable; // 注意:对象如果需要序列化,必须实现序列化接口。
public class User implements Serializable {
    private String loginName; //登录名
    private String userName; //用户名
    private int age; //年龄
    // transient 这个成员变量将不参与序列化。
    private transient String passWord;

    public User() {
    }

    public User(String loginName, String userName, int age, String passWord) {
        this.loginName = loginName;
        this.userName = userName;
        this.age = age;
        this.passWord = passWord;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

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

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    @Override
    public String toString() {
        return "User{" +
                "loginName='" + loginName + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", passWord='" + passWord + '\'' +
                '}';
    }
}

package com.liu.d6_object_stream;

import java.io.FileInputStream;
import java.io.ObjectInputStream;

/**
 * 目标:掌握对象字节输入流的使用:反序列化对象。
 */
public class Test2ObjectInputStream {
    public static void main(String[] args) {
        try (
                // 1、创建一个对象字节输入流管道,包装 低级的字节输入流与源文件接通
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io-app2/src/itheima11out.txt"));
        ){
            User u = (User) ois.readObject(); //强转成用户对象
            System.out.println(u);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果要一次序列化多个对象,咋整?

  • 用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可
  • 注意:ArrayList集合已经实现了序列化接口!
     

对象序列化的含义是什么?怎么实现对象序列化?需要注意什么?

  • 把对象数据存入到文件中去。
  • 对象字节输出流ObjectOutputStram
  • public void writeObject(Object obj)
  • 对象必须实现序列化接口

对象反序列化的含义是什么?怎么实现对象反序列化?

  • 把对象数据存入到文件中去。
  • 对象字节输入流ObjectInputStram
  • public Object readObject()

IO流(二):补充知识:IO框架


什么是框架

  • 解决某类问题,编写的一套类、接口等,可以理解成一个半成品,大多框架都是第三方研发的。
  • 好处:在框架的基础上开发,可以得到优秀的软件架构,并能提高开发效率
  • 框架的形式:一般是把类、接口等编译成class形式,再压缩成一个.jar结尾的文件发行出去。

什么是IO框架?

  • 封装了Java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。

Commons—io

  • Commons-io是apache开源基金组织提供的一组有关IO操作的小框架,目的是提高IO流的开发效率。
     

package com.liu;

import java.nio.file.Files;

/**
 * 目标:使用CommonsIO框架进行IO相关的操作。
 */
public class CommonsIOTest1 {
    public static void main(String[] args) throws Exception {
//        FileUtils.copyFile(new File("io-app2\\src\\itheima01.txt"), new File("io-app2/src/a.txt"));
//        FileUtils.copyDirectory(new File("D:\\resource\\私人珍藏"), new File("D:\\resource\\私人珍藏3"));
//        FileUtils.deleteDirectory(new File("D:\\resource\\私人珍藏3"));

        // Java提供的原生的一行代码搞定很多事情
        // Files.copy(Path.of("io-app2\\src\\itheima01.txt"), Path.of("io-app2\\src\\b.txt"));
        System.out.println(Files.readString(Path.of("io-app2\\src\\itheima01.txt")));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值