018.day18 map集合如何实现排序 File类 IO流 字节流 字符流 编码

目录

文件操作和IO流

复习

一、map集合如何实现排序

// TODO HashMap - key为一个引用类型(自定义类型)
        // 定义Hash结构的Map集合
        Map<Student, Integer> student = new HashMap<>();
        // 根据存放顺序有序
        student.put(new Student("sand", 18), 5);
        student.put(new Student("tom", 19), 2);
        student.put(new Student("tom", 19), 3);
        student.put(new Student("jerry", 20), 4);
        for (Map.Entry<Student, Integer> temp : student.entrySet()) {
            System.out.println(temp);
        }
//Student [name=tom, age=19]=3
//Student [name=jerry, age=20]=4
//Student [name=sand, age=18]=5
        // 将集合当中的元素重新排序
        // 将一个Map结合中的键值对作为ArrayList的元素,直接转换为ArrayList
        ArrayList<Map.Entry<Student, Integer>> list = new ArrayList<>(student.entrySet());
        // list集合中存储顺序与map集合一致
        for (Entry<Student, Integer> entry : list) {
            System.out.println(entry);
        }
//Student [name=tom, age=19]=3
//Student [name=jerry, age=20]=4
//Student [name=sand, age=18]=5
        // 借助Collections工具类中的sort方法
        // 第一个参数为List接口的实现类
        // 第二个参数为匿名内部类实现的比较器,或者是实现了外部比较器接口的类的实例
        Collections.sort(list, new StudentComparator());
        // 当前的排序结果记录在list当中
        for (Entry<Student, Integer> entry : list) {
            System.out.println(entry);
        }
//此时已经实现了排序,排序规则是在StudentComparator()中根据student类年龄升序排序
//Student [name=sand, age=18]=5
//Student [name=tom, age=19]=3
//Student [name=jerry, age=20]=4
public class StudentComparator implements Comparator<Entry<Student, Integer>> {
    // 指定比较器的泛型为Map.Entry<Student, Integer>
    @Override
    public int compare(Entry<Student, Integer> o1, Entry<Student, Integer> o2) {
        // o1代表当前对象,o2代表已经存在的对象
        // Integer当中已经实现了自然排序接口,默认升序
        // value中记录的是元素的存入顺序
        // 可以直接调用compareTo方法使得集合按照map当中的value升序
        // return o1.getValue().compareTo(o2.getValue());
        // 针对key进行排序
        // 如果key是一个自定义类型的实例,也可以在类的定义结构中实现自然排序接口,编写相应的比较规则,直接调用
        return o1.getKey().compareTo(o2.getKey());
    }

}
public int compareTo(Student o) {
        // 需求:向TreeSet集合当中存放Student对象,使得对象之间根据年龄升序
        // 当两个对象属性完全相同时,认定是重复对象,返回0
        Student student = null;
        // 1.判断实例的类型
        if (o instanceof Student) {
            student = (Student) o;
        }else {
            // 如果待比较元素不是Student类型,不予添加
            return 0;
        }
        if (this.name.equals(student.getName()) && this.age == student.getAge()) {
            // 当两个比较对象各属性相同时,认定相同,不予添加
            return 0;
        }
        // 2.年龄的比较
        if (this.age >= student.getAge()) {
            // 通过正负来决定位置
            // 正数放后
            // 负数放前
            return 1;
        }else {
            return -1;
        }
    }
  • 练习
// TODO HashMap练习:1.根据商品价格升序/降序 2.根据存放顺序
        Map<Product, Integer> map = new HashMap<>();
        // 0.准备数据,构建集合
        map.put(new Product("生活用品", 200), 1);
        map.put(new Product("电子产品", 300), 2);
        map.put(new Product("日常用品", 150), 3);
        map.put(new Product("食品", 400), 4);
        // 1.将集合转换为ArrayList
        // 泛型与定义保持一致
        ArrayList<Map.Entry<Product, Integer>> list = new ArrayList<>(map.entrySet());
        // 2.自定义比较器,以一个实例的方式传入
        Collections.sort(list, new ProductComparator());
        // 3.输出结果
        for (Map.Entry<Product, Integer> entry : list) {
            System.out.println(entry);
        }
        
        Collections.sort(list, new Comparator<Map.Entry<Product, Integer>>() {
            // value当中记录了存放顺序
            // Integer实现类自然排序接口
            // 默认升序与value的顺序一致
            @Override
            public int compare(Entry<Product, Integer> o1, Entry<Product, Integer> o2) {
                // 获得值
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        System.out.println();
        // 3.输出结果
        for (Map.Entry<Product, Integer> entry : list) {
            System.out.println(entry);
        }
  • 数据分析的helloword
// TODO 单词计数:统计每个单词出现的总次数
        // 0.数据准备
        String[] lines = new String[4];
        lines[0] = "good good study";
        lines[1] = "day day up";
        lines[2] = "I am sand";
        lines[3] = "I am a boy good";
        // 1.遍历数据 -> 获取到每一个单词
        Map<String, Integer> result = new HashMap<>();
        for (String line : lines) {
            for (String word : line.split(" ")) {
                // word -> 获取到的每一个单词
                // 2.当第一次添加时,次数记为1;后续添加时,累加次数
                // result.get(word) == null
                // 当集合当中不包含相应的key(统计的单词) -> 第一次添加进来 -> 次数记为1
                if (!result.containsKey(word)) {
                    result.put(word, 1);
                }else {
                    // 非首次添加,将次数进行累加
                    // int count = result.get(word) + 1;
                    // result.put(word,count)
                    result.put(word, result.get(word) + 1);
                }
            }
        }
        // 3.输出结果
        for (Map.Entry<String, Integer> temp : result.entrySet()) {
            System.out.println(temp);
        }

本节任务

I/O流

File类的使用

字节流和字符流

教学目标

了解I/O流的概念

掌握File类的使用

掌握字节流的使用

掌握字符流的使用

教学内容

一、File类

在Java中,使用File类对磁盘上的文件(夹)进行操作

1. 构造方法

2. 字段

  • pathSeparator:与系统有关的路径分隔符,Windows下为分号,Linux下为冒号
  • pathSeparatorChar:同上,以一个字符的形式存在
  • separator:与系统有关的名称分隔符,Windows下为反斜杠,Linux下为斜杠
  • separatorChar:同上,以一个字符的形式存在

    3. 方法

// TODO File类-文件路径
        // 创建File的实例,其中包含了路径信息
        // File的构造器,以字符串的形式指定路径
        File file1 = new File("E://test");
        // 文件(文件夹)的绝对路径
        System.out.println(file1.getAbsolutePath());//E:\test
        // 文件(文件夹)的标准路径
        System.out.println(file1.getCanonicalPath());//E:\test
        // "" -> 空字符串时能够代表当前路径 -> 可以获得绝对路径 -> 不能执行文件相关操作
        // "文件名/路径" -> 从当前路径开始,拼接当前路径,获得一个完整的路径
        // "/" -> 斜杠:当前能够到达的根目录 (Windows:所在盘符/Linux:根路径)
        // 使用斜杠时以程序执行的位置有关,会获取当前所在盘符
// TODO File类-构造器
        File parent = new File("E://test");
        // 直接传入File对象作为父级路径
        File child1 = new File(parent, "b");
        System.out.println(parent.getAbsolutePath());
        System.out.println(child1.getAbsolutePath());
        // 直接传入父级路径的字符串
        File child2 = new File(parent.getPath(), "a");
        System.out.println(child2.getAbsolutePath());
// TODO File类 - 文件查看 - 练习:输出某一路径下的所有文件(夹)
        File file = new File("E://test");
        // 判断路径是否存在
        if (!file.exists()) {
            // 不存在则创建一个文件夹,返回值为boolean类型
            file.mkdir();
        }
        // 获取当前路径下的所有文件(夹)
        getFiles(file);
    }
    
    /**
     * 递归的方式获得某一路径下的所有文件(夹)信息
     * @param file 指定某一个存在的路径
     */
    public static void getFiles(File file) {
        // 完全打印当前目录下的文件夹的内容
        for (File child : file.listFiles()) {
            // 打印当前目录下的子文件(夹)
            System.out.println(child);
        }
        for (File child : file.listFiles()) {
            // 判断该路径文件是否是一个文件夹
            if (child.isDirectory()) {
                // 如果子目录是一个文件夹,把其当成一个新的目录,遍历里面的子目录
                getFiles(child);
            }
        }
// TODO 路径相关的分隔符
        // 各级路径之间的分隔符(文件(夹)与文件(夹)之间的分隔符)
        // Windows下可以使用/(斜杠)和\(反斜杠)
        // Linux下只能使用斜杠
        // 解决跨平台下的路径的兼容问题
        System.out.println(File.separator);
        // 路径与路径之间的分隔符
        System.out.println(File.pathSeparator);
// TODO File的删除 - 非空目录
{
    File file = new File("E:/test");
        if (!file.exists()) {
            file.mkdirs();
        }
        delete(file);
}
public static void delete(File file) {
        // 如果是空文件夹则直接删除
        if (file.delete()) {
            return;
        }else {
            // 非空文件夹
            for (File child : file.listFiles()) {
                // 尝试删除文件及文件夹
                // 对于非空文件夹会进入if结构
                // 即使不触发if,删除行为也会进行,例如:删除文件时删除成功,此时if中的值为false
                if (!child.delete()) {
                    delete(child);
                }
            }
            // 删除所传入路径的最外层文件夹
            file.delete();
        }
// TODO File类的方法
        File file = new File("E:/test");
        System.out.println(file.canExecute());//执行:进入文件夹
        System.out.println(file.canRead());//读->查看文件夹中的信息
        System.out.println(file.canWrite());//写:修改文件夹内容
        // 指定的路径文件不存在时,可以创建一个新的文件
        File file2 = new File(file,"aa.txt");
        file2.createNewFile();
        // 创建所有不存在的父级目录
        File file3 = new File(file,"qq/ww/ee");
        file3.mkdirs();
        // getParentFile() -> 父级路径的File对象,以最后一级目录作为当前路径,返回剩余的路径信息
        System.out.println(file3.getParentFile().getAbsolutePath());//E:\test\qq\ww
        File file4 = new File("E:/");
        // 当前路径已经在根目录,则返回null(返回空对象)
        // getParent -> 获取父级路径的字符串
        System.out.println(file4.getParentFile());//null

二、IO流

I:input,O:output,通常指对磁盘文件内容的读写操作,通过一个媒介或管道将文件与内存进行交互,这个媒介就被成为I/O流,流的本质为数据传输

1. 按流向分类

  • 输入流:将数据读取到程序(内存)中使用的流
  • 输出流:从程序(内存)向外输出数据使用的流

    2. 按单位分类

  • 字符流:一次传输一个字符的数据,将数据以字符的形式传输
  • 字节流:一次传输一个字节的数据,将数据以字节的形式传输

    3. 按层次分类

  • 节点流:可以从/向一个特定的节点读写数据的流
  • 处理流:对已存在的流的封装,通过封装的流的功能调用实现数据读写

    三、字节流

    1. 字节输入流

    InputStream是一个抽象类,不能直接实例化对象

  • 相关方法

// TODO 字节流 - 读取文件(输入流)
        // 借助工具类 -> 每次读取若干个字节(一个或多个) -> 将读取到的数据转换为char类型输出原信息
        // 中文字符需要编码处理
        // 1.指定一个要读取的文件路径
        File file = new File("E:/test.txt");
        // 2.初始化相关的对象
        InputStream inputStream = new FileInputStream(file);
        int i = -1;
        String result = "";
        // 3.读取文件中所有的内容 - read()方法
        // 赋值的同时进行判断 -> 将获取到的值记录在某一个变量中,判断时直接使用变量值判断,同时变量值可以正常使用
        while((i = inputStream.read()) != -1) {
            result += (char)i;
        }
        // 4.将读取到的信息输出
        System.out.println(new String(result.getBytes("iso-8859-1"),"UTF-8"));
        inputStream.close();

2. 字节输出流

OutputStream是抽象类,不能直接实例化对象

// TODO 字节输出流
        // 输出到磁盘的文件中
        // 输出流重要参数:是否续写(apped),默认为flase
        // 1.指定文件路径
        File file = new File("E:/test.txt");
        // 2.初始化字节输出流
        OutputStream outputStream = new FileOutputStream(file,true);
        // \r\n -> 在Windows中使用\r\n作为换行符,Linux中使用\n
        // 3.向路径中写入信息(以byte形式)
        outputStream.write("\r\n789续写".getBytes());
        outputStream.close();
  • 小练习

    • 字节流文件复制

      // TODO 字节流文件复制
      public static void main(String[] args) throws IOException {
              copy("f:/test.txt", "f:/aa/testCopy.txt");
          }
      
          /**
           * 字节流文件复制
           * 
           * @param src
           *            源文件路径
           * @param dest
           *            目标文件路径
           */
          public static void copy(String src, String dest) {
              // 1.使用File指定文件路径
              File srcFile = new File(src);
              File destFile = new File(dest);
              // 2.文件校验
              // 源文件不存在,方法直接结束
              if (!srcFile.exists()) {
                  System.out.println("源文件不存在");
                  return;
              }
              // 目标文件路径父级路径不存在
              if (!destFile.getParentFile().exists()) {
                  destFile.getParentFile().mkdirs();
              }
              // 目标文件不存在则创建
              if (!destFile.exists()) {
                  try {
                      destFile.createNewFile();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
              // 3.初始化输入输出流
              InputStream inputStream = null;
              OutputStream outputStream = null;
              try {
                  inputStream = new FileInputStream(srcFile);
                  outputStream = new FileOutputStream(destFile,false);
              } catch (FileNotFoundException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
              // 4.文件复制
              // length代表本次读取到的字节数,-1时代表到达文件末尾
              int length = -1;
              // 将每次读取到的数据放入byte数组当中
              // 使用字节数组的方式可以提高读写效率
              byte[] data = new byte[1024];
              try {
                  while ((length = inputStream.read(data)) != -1) {
                      // 写入byte数组中的数据,同时指定偏移量,从数组开头,一直到当前从源文件中读取的数据长度
                      outputStream.write(data,0,length);
                  }
                  // 5.关闭输入输出流
                  inputStream.close();
                  outputStream.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
    • 字节流练习:文件内容比较

      public static void main(String[] args) {
              // TODO 字节流练习:文件内容比较
              System.out.println(compare("E:/test.txt", "E:/testCopy.txt"));
          }
      
          /**
           * 比较两个文件的内容是否完全一致
           * @param c1 比较文件A
           * @param c2 比较文件B
           * @return 两个文件是否相同
           */
          public static boolean compare(String c1,String c2) {
              // 1.使用File指定文件路径
              File cFile1 = new File(c1);
              File cFile2 = new File(c2);
              // 2.文件校验
              if (!cFile1.exists() || !cFile2.exists()) {
                  System.out.println("请检查源文件路径");
                  return false;
              }
              // 3.初始化输入流
              InputStream inputStreamC1 = null;
              InputStream inputStreamC2 = null;
              try {
                  inputStreamC1 = new FileInputStream(cFile1);
                  inputStreamC2 = new FileInputStream(cFile2);
              } catch (FileNotFoundException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
              // 4.文件内容比较
              int i = -1;
              int j = -1;
              // 结果初始值为true
              boolean result = true;
              try {
                  // 每次用i和j记录读取到的数据,当达到文件末尾时,值为-1
                  // &&/||逻辑运算有时会出现短路,当第一个结果已经能够决定整个表达式运算结果时,第二个表达式不会执行
                  // 可以使用位运算符
                  while ((i = inputStreamC1.read()) != -1 | (j = inputStreamC2.read()) != -1) {
                      // 每次读取到的字符进行比较
                      if (i != j) {
                          // 如果出现不相等,两个文件不相同,直接跳出
                          result = false;
                          break;
                      }
                  }
                  // 当某一个文件提前结束,i和j当中一定有一个为-1
                  // 此时i和j不相等
                  /*if (i != j) {
                      result = false;
                  }*/
              } catch (IOException e) {
                  e.printStackTrace();
              }
              return result;
          }

3. 文件输入流

以字节流的形式读取一个文件中的数据

  • FileInputStream:使用File作为参数初始化,指定要读取的文件

  • read()方法:每次读取一个字节

    // TODO 字符流输入流
          // 1.初始化字符流
          // 需要一个InputStream -> 实现类
          Reader reader = new InputStreamReader(new FileInputStream(new File("f:/test.txt")));
          // 2.读取文件中的数据
          int i = -1;
          while ((i = reader.read()) != -1) {
              System.out.print((char)i);
          }
          // 3.关闭流
          reader.close();
// TODO 字符流一次读入多个字符
        // 1.初始化字符流
        // 需要一个InputStream -> 实现类
        Reader reader = new InputStreamReader(new FileInputStream(new File("f:/test.txt")));
        // 2.读取文件中的数据
        // 当前次读取到的字符个数
        int length = -1;
        // 每次读取的最大字符数
        char[] cs = new char[5];
        while ((length = reader.read(cs)) != -1) {
            // 最后一次(临近文件末尾)不一定会装满字符数组,此时以length为准
            for (int j = 0; j < length; j++) {
                System.out.print((char) cs[j]);
            }
        }
        // 3.关闭流
        reader.close();

4. 文件输出流

  • FileOutputStream:使用File作为参数初始化,指定要写入的文件
  • write(byte[] b)方法:从指定byte数组中将数据写入此文件输出流中
// TODO 字符流的输出流
        // 1.初始化字符输出流
        Writer writer = new OutputStreamWriter(new FileOutputStream(new File("E:/test.txt"),true));
        // 2.使用字符流的方式写入数据
        writer.write("!字符流输出!");
        // 3.使用flush方法将缓冲区的数据写入文件
        writer.flush();
        // 流关闭时也会释放缓冲区
        // 4.关闭流
        writer.close();
  • 小练习
// TODO 使用字符流实现文件的复制
        copy("E:/test.txt", "E:/aa/bb/testCopy.txt");
    }

    public static void copy(String src,String dest) {
        // 1.初始化文件路径
        File srcFile = new File(src);
        File destFile = new File(dest);
        // 2.路径校验
        if (!srcFile.exists()) {
            System.out.println("源文件不存在");
            return;
        }
        if (!destFile.getParentFile().exists()) {
            // 自动创建父级目录
            destFile.getParentFile().mkdirs();
        }
        // 3.初始化需要的流
        Reader reader = null;
        Writer writer = null;
        try {
            reader = new InputStreamReader(new FileInputStream(srcFile));
            writer = new OutputStreamWriter(new FileOutputStream(destFile));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 4.字符流方式文件复制
        int length = -1;
        char[] data = new char[5];
        try {
            while ((length = reader.read(data)) != -1) {
                writer.write(data, 0, length);
                writer.flush();
            }
            // 5.关闭输入输出流
            reader.close();
            writer.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

四、字符流

1. 输入流

抽象父类:Reader

  • 子类:InputStreamReader,FileReader
  • 初始化字符输入流:需要一个文件流
  • 初始化文件流:需要一个File对象(包含路径信息)
// 细化写法
File file = new File("E:/test.txt");
InputStream inputStream = new FileInputStream(file);
Reader reader = new InputStreamReader(inputStream);
// 简化写法
Reader reader = new InputStreamReader(new FileInputStream(new File("E:/test.txt")));
  • read():每次读取一个字符(中英文均可),读取到文件末尾返回-1
  • 可以一次读取多个字符

2. 字符输出流

2. 输出流

抽象父类:Writer

  • 子类:OutputStreamWriter,FileWriter
  • 初始化字符输出流:需要一个文件流
  • 初始化文件流:需要一个File对象(包含路径信息)
// 细化写法
File file = new File("E:/test.txt"); 
OutputStream inputStream = new FileOutputStream(file); 
Reader reader = new OutputStreamWriter(inputStream);
// 简化写法
Writer writer = new OutputStreamWriter(new FileOutputStream(new File("E:/test.txt")));
  • write(String str):可以直接向目标写入字符串
  • flush():刷新缓冲,对于有缓冲区的流都应调用该方法

五、编码

文本内容必须经过正确的编码和解码才能够正常显示,但有些时候我们可以通过ISO-8859-1编码来获得一个正确的表示

  • 字符串编码:getBytes(String charsetName)方法获得一个byte数组
  • 解码显示:new String(byte[] bytes,charsetName)
  • 解码方式和编码方式相同时,可以正常显示
  • UTF-8以及GBK格式经过ISO-8859-1解码再编码后,数据不丢失
  • UTF-8格式经过GBK解码再编码后,数据不丢失

猜你喜欢

转载自www.cnblogs.com/yokii/p/9441840.html