java - java进阶(三)Stream、File、IO流

一、Stream

1、获取Stream流

获取Stream流对象
	- 将数据放在流水线的传送带上
	
	1. 集合获取 Stream 流对象(使用Collection接口中的默认方法)
	    default Stream<E> stream()
	
	    * Map集合获取Stream流对象,需要间接获取
	        - map.entrySet()
	
	2. 数组获取 Stream 流对象(使用Arrays数组工具类中的静态方法)
	    static <T> Stream<T> stream(T[] array)
	
	3. 零散数据获取 Stream 流对象(使用Stream 类中的静态方法)
	    static <T> Stream<T> of(T... values)
package com.itheima.stream;

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

public class StreamDemo1 {
    public static void main(String[] args) {
		// 零散数据获取Stream流对象
        Stream.of(1, 2, 3, 4, 5, 6).forEach(s -> System.out.println(s));
        Stream.of("张三", "李四", "王五", "赵六").forEach(s -> System.out.println(s));
    }

	// 数组获取 Stream 流对象
    private static void method2() {
        int[] arr1 = {11, 22, 33};
        double[] arr2 = {11.1, 22.2, 33.3};

        Arrays.stream(arr1).forEach(value -> System.out.println(value));
        Arrays.stream(arr2).forEach(s -> System.out.println(s));
    }

	// 集合获取 Stream 流对象
    private static void method1() {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("张良");
        list.add("王二麻子");
        list.add("谢广坤");
        list.add("张三丰");
        list.add("张翠山");

//        Stream<String> s1 = list.stream();
//        s1.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
        list.stream().forEach(s -> System.out.println(s));

        Set<String> set = new HashSet<>();
        set.add("张无忌");
        set.add("张良");
        set.add("王二麻子");
        set.add("谢广坤");
        set.add("张三丰");
        set.add("张翠山");
        set.stream().forEach(s -> System.out.println(s));

		// Map集合获取Stream流对象,需要间接获取
        Map<String, Integer> map = new HashMap<>();
        map.put("张三丰", 100);
        map.put("张无忌", 35);
        map.put("张翠山", 55);
        map.put("王二麻子", 22);
        map.put("张良", 30);
        map.put("谢广坤", 55);

//        Set<String> keySet = map.keySet();
//        keySet.stream();
//        Collection<Integer> values = map.values();
//        values.stream();

        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        entrySet.stream().forEach(s -> System.out.println(s.getKey() + "---" + s.getValue()));
    }
}

2、Stream流中间操作方法

Stream 流的中间操作方法
	- 操作后返回Stream对象,可以继续操作
	
	Stream<T> filter(Predicate<? super T> predicate)	用于对流中的数据进行过滤
	Stream<T> limit(long maxSize)	获取前几个元素
	Stream<T> skip(long n)	跳过前几个元素
	Stream<T> distinct()	去除流中重复的元素依赖 (hashCode 和 equals方法)
	        - 依赖hashCode和equals方法
	static <T> Stream<T> concat(Stream a, Stream b)	合并a和b两个流为一个流
	
	注意事项:
	    流对象已经被消费过(使用过),就不允许再次消费了
package com.itheima.stream;

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

public class StreamDemo2 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");
		
		// 需求: 将集合中以【张】开头的数据过滤出来并打印在控制台
        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
        System.out.println("------------------------------");

        // 需求1: 取前3个数据在控制台输出
        list.stream().limit(3).forEach(s -> System.out.println(s));
        System.out.println("-------------------------------");
        // 需求2: 跳过3个元素,把剩下的元素在控制台输出
        list.stream().skip(3).forEach(s -> System.out.println(s));
        System.out.println("-------------------------------");
        // 需求3: 跳过3个元素,在剩下的元素中前2个在控制台输出
        list.stream().skip(3).limit(2).forEach(s -> System.out.println(s));
        System.out.println("-------------------------------");
        // 需求4: 取前4个数据组成一个流
        Stream<String> s1 = list.stream().limit(4);
        // 需求5: 跳过2个数据组成一个流
        Stream<String> s2 = list.stream().skip(2);
        // 需求6: 合并需求4和需求5得到的流,并把结果在控制台输出
        Stream<String> s3 = Stream.concat(s1, s2);
//        s3.forEach(s -> System.out.println(s));
        System.out.println("-------------------------------");
        // 需求7: 合并需求4和需求5得到的流,并把结果在控制台输出,要求字符串元素不能重复
        s3.distinct().forEach(s -> System.out.println(s));
    }
}

3、Stream流终结方法

Stream 流的终结操作方法
	- 流水线中的最后一步工序
	
	public void forEach(Consumer action)	对此流的每个元素执行遍历操作
	public long count()	返回此流中的元素数
package com.itheima.stream;

import java.util.stream.Stream;

public class StreamDemo3 {
    public static void main(String[] args) {
        long count = Stream.of(1, 2, 3, 4, 5, 6).filter(s -> s % 2 == 0).count();
        System.out.println(count);
    }
}

4、Stream流收集方法

public R collect(Collectors c)   将流中的数据收集到集合
	Collectors : 
	    public static <T> Collector toList()
	    public static <T> Collector toSet()
	    public static Collector toMap(Function keyMapper, Function valueMapper)
package com.itheima.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo4 {
    public static void main(String[] args) {

        List<Integer> list1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).filter(s -> s % 2 == 0).collect(Collectors.toList());
        System.out.println(list1);

        Set<Integer> set = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).filter(s -> s % 2 == 0).collect(Collectors.toSet());
        System.out.println(set);

        /*
            创建一个ArrayList集合,病添加一下字符串
                "张三,23"
                "李四,24"
                "王五,25"
                保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
         */
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("张三,23");
        list2.add("李四,24");
        list2.add("王五,25");
        Map<String, Integer> map = list2.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return Integer.parseInt(s.split(",")[1]) >= 24;
            }
        }).collect(Collectors.toMap(new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s.split(",")[0];
            }
        }, new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s.split(",")[1]);
            }
        }));
        System.out.println(map);
    }
}

二、File

1、File的构造方法

File类介绍: 文件或文件夹对象

	构造方法:
	    public File(String pathname)	根据文件路径创建文件对象
	    public File(String parent, String child)	根据父路径名字符串和子路径名字符串创建文件对象
	    public File(File  parent, String child)	根据父路径对应文件对象和子路径名字符串创建文件对象
package com.itheima.file;

import java.io.File;
import java.io.IOException;

public class FileDemo1 {
    public static void main(String[] args) throws IOException {
        File f1 = new File("D:\\A.txt");
        f1.createNewFile();

        File f2 = new File("D:\\tempfiles");
        System.out.println(f2.exists()); // true

        File f3 = new File("D:\\", "tempfiles");
        System.out.println(f3.exists()); // true

        File f4 = new File(new File("D:\\"), "tempfiles");
        System.out.println(f4.exists()); // true
    }
}

2、相对路径与绝对路径

路径的写法

	1. 绝对路径: 从盘符根目录开始,一直到某个具体的文件或文件夹
	2. 相对路劲: 相对于当前项目
package com.itheima.file;

import java.io.File;
import java.io.IOException;

public class FileDemo2 {
    public static void main(String[] args) throws IOException {
        File f1 = new File("");
        System.out.println(f1.getAbsolutePath()); // F:\\JavaCode\\code5

        File f = new File("day20-h-code\\src\\com\\itheima\\file\\A.txt");
        f.createNewFile();
    }
}

3、File常见方法

1. 判断相关
    public boolean isDirectory() : 判断此路径名表示的File是否为文件夹
    public boolean isFile() : 判断此路径名表示的File是否为文件
    public boolean exists() : 判断此路径名表示的File是否存在

2. 获取相关
    public long length() : 返回文件的大小(字节数量)
            * 文件对象操作,返回正确的字节个数
            * 文件夹对象操作,返回的是错误的字节个数
    public String getAbsolutePath() : 返回文件的绝对路径
    public String getPath() : 返回定义文件时使用的路径
    public String getName() : 返回文件的名称,带后缀
    public long lastModified() : 返回文件的最后修改时间(时间毫秒值)
package com.itheima.file;

import java.io.File;
import java.util.Date;

public class FileMethodDemo3 {
    public static void main(String[] args) {
        File f1 = new File("D:\\A.txt");
        System.out.println(f1.isDirectory()); // false
        System.out.println(f1.isFile()); // true
        System.out.println(f1.exists()); // true

        System.out.println("====================================");
        File f2 = new File("D:\\tempfiles");
        System.out.println(f1.length()); // 3
        System.out.println(f2.length()); // 0

        System.out.println("===================================");
        File f3 = new File("A.txt");
        System.out.println(f3.getAbsolutePath()); // F:\JavaCode\code5\A.txt

        System.out.println("====================================");
        System.out.println(f1.getName()); // A.txt
        System.out.println(f2.getName()); // tempfiles
        System.out.println(f3.getName()); // A.txt

        System.out.println("====================================");
        long time = f1.lastModified();
        System.out.println(new Date(time)); // Sun Sep 03 11:26:42 CST 2023
    }
}

4、File创建与删除

public boolean createNewFile() : 创建一个新的空的文件
public boolean mkdir() : 只能创建一级文件夹
public boolean mkdirs() : 可以创建多级文件夹
public boolean delete() : 删除由此抽象路径名表示的文件或空文件夹
        * delete 方法只能删除空文件夹,且不走回收站
package com.itheima.file;

import java.io.File;
import java.io.IOException;

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

        File f1 = new File("day20-h-code\\src\\com\\itheima\\file\\B.txt");
        System.out.println(f1.createNewFile());

        System.out.println("=================================");
        File f2 = new File("day20-h-code\\src\\com\\itheima\\aaa\\bb\\cc");
        System.out.println(f2.mkdirs());

        System.out.println("=================================");
        File f3 = new File("day20-h-code\\src\\com\\itheima\\aaa.txt");
        System.out.println(f2.mkdirs()); // true

        System.out.println("=================================");
        System.out.println(f1.delete());
        System.out.println(f2.delete());
    }
}

5、File的遍历

public File[] listFiles() : 获取当前目录下所有的 “一级文件对象” 返回file数组
    * 当调用者File表示的路径不存在时,返回null
    * 当调用者File表示的路径是文件时,返回null
    * 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
    * 当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
package com.itheima.file;

import java.io.File;

public class FileMethodDemo5 {
    public static void main(String[] args) {
        File f = new File("D:\\tempfiles");
        File[] files = f.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

6、示例

package com.itheima.file;

import java.io.File;
import java.util.Scanner;

public class FileTest1 {

    /*
        需求 :  键盘录入一个文件夹路径,如果输入错误就给出提示,并继续录入,直到正确为止

        分析:
            1. 输入的路径有可能不存在
            2. 输入的路径有可能是文件路径

            封装为File对象
                调用 exists() 判断是否存在
                调用 isFile() 判断是否是文件
     */
    public static void main(String[] args) {
        File dir = getDir();
        System.out.println(dir);
        printJavaFile(dir);
        deleteDir(new File("D:\\wltBak"));
        System.out.println(getLength(dir));
		
		getCount(dir);
        hm.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println(s + ": " + integer);
            }
        });
        System.out.println("没有后缀名文件的个数为: " + count);
    }

    public static File getDir() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入文件夹路径:");
        while (true) {
            String path = sc.nextLine();

            File dir = new File(path);
            if (!dir.exists()) {
                System.out.println("您输入的文件夹路径不存在,请重新输入:");
            } else if (dir.isFile()) {
                System.out.println("您输入的是一个文件路径,请重新输入一个文件夹路径:");
            } else {
                return dir;
            }
        }
    }

    /**
     * 需求:键盘录入一个文件夹路径,找出这个文件夹下所有的 .java 文件
     * 对接收到的文件夹路径进行遍历,找出所有的.js文件
     */
    public static void printJavaFile(File dir) {
        // 1.获取当前路径下所有的文件和文件夹对象
        File[] files = dir.listFiles();
        // 2.对数组遍历,获取每一个文件或文件夹对象
        for (File file : files) {
            // 3.判断是否是 .java文件
            if (file.isFile() && file.getName().endsWith(".java")) {
                System.out.println(file);
            } else if (file.isDirectory()) {
                // 4.是文件夹,继续调用
                if (file.listFiles() != null) {
                    printJavaFile(file);
                }
            }
        }
    }

	/*
        需求: 设计一个方法,删除文件夹(delete() 只能删除空文件夹)
     */
    public static void deleteDir(File dir) {
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                // 文件直接删除
                file.delete();
            } else {
                // 文件夹,进入文件夹继续删除
                if (file.listFiles() != null) {
                    deleteDir(file);
                }
            }
        }

        // 循环结束后,删除空文件
        dir.delete();
    }
    
    /*
        需求: 键盘录入一个文件夹路径,统计文件夹的大小
     */
    public static long getLength(File dir) {
        long sum = 0;
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                sum += file.length();
            } else {
                if (file.listFiles() != null) {
                    sum += getLength(file);
                }
            }
        }
        return sum;
    }

	 /*
        需求:键盘录入一个文件夹路径,统计文件夹中每种文件的个数并打印(考虑子文件夹)

        打印格式如下:
            txt:3个
            doc:4个
            jpg:6个
     */
    static HashMap<String, Integer> hm = new HashMap<>();
    static int count = 0;

    public static void getCount(File dir) {
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isFile()) {
                // 1.获取文件名
                String name = file.getName();

                if (name.contains(".")) {
                    // 2.获取后缀名
                    String[] arr = name.split("\\.");
                    String type = arr[arr.length - 1];

                    // 3.统计
                    if (hm.containsKey(type)) {
                        hm.put(type, hm.get(type) + 1);
                    } else {
                        hm.put(type, 1);
                    }
                } else {
                    // 没有后缀名,单独统计
                    count++;
                }
            } else {
                if (file.listFiles() != null) {
                    getCount(file);
                }
            }
        }
    }
}

三、IO流

I : input 输入(读取)
O : output 输出(写出)

1、IO流体系结构

在这里插入图片描述

2、FileOutputStream 字节输出流

字节输出流写出数据

	构造方法:
	        1. public FileOutputStream(String name[, boolean append]) : 输出流关联文件,文件路径以字符串形式输出
	        2. FileOutputStream(File file[, boolean append]) : 输出流关联文件,文件路径以File对象形式给出
	            - boolean append 追加写入的开关
	
	成员方法:
	        public void write(int i) : 写出一个字节
	        public void write(byte[] bys) : 写出一个字节数组
	        public void write(byte[] bys, int off, int len) : 写出字节数组的一部分
	
	注意:
	        输出流关联文件,文件如果不存在,会自动创建出来
	                        					如果存在,会清空现有的内容,然后再进行写入操作
	
	标准的关流代码
	    jdk7版本之前
	        FileOutputStream fos = null;
	        try {
	            System.out.println(10 / 0);
	            fos = new FileOutputStream("F://b.txt");
	            fos.write("abc".getBytes());
	        } catch (IOException e) {
	            e.printStackTrace();
	        } finally {
	            if (fos != null) {
	                try {
	                    fos.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	
	    jdk7版本之后
	        try (需要调用close方法的对象) {
	            逻辑代码
	        } catch (异常类名 对象名) {
	            异常处理方式
	        }
	        
	        注意:
	            try() 中的对象,需要实现过 AutoCloseable 接口
package com.itheima.stream.output;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo1 {
    public static void main(String[] args)  {
        // 创建字节输出流对象,关联文件
        try (FileOutputStream fos = new FileOutputStream("F://a.txt", true)) {
            byte[] bys = {100, 101, 102};
            // 写出数据
            fos.write(97);
            fos.write(98);
            fos.write(99);
            fos.write(bys);
            fos.write("你好你好".getBytes());
            fos.write(bys, 1, 2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3、FileInputStream 字节输入流

字节输入流读取数据

    构造方法
        FileInputStream(String name) : 输入流关联文件, 文件路径以字符串形式给出
        FileInputStream(File file) : 输入流关联文件, 文件路径以File对象形式给出

    成员方法
        public int read() : 读取单个字节,如果到达文件末尾则返回 -1
        public int read(byte[] b) : 将读取到字节放到传入的数据,返回读取到的有效字节个数,如果到达末尾则返回 -1

    注意事项
        1.关联的文件不存在会抛出 FileNotFoundException 异常
        2.文件夹的话会拒绝访问

    构造方法
        public String(byte[] bytes, int off, int len) : 将字节数组转换为字符串
            byte[] bytes : 字节数组
            int off : 起始索引
            int len : 转换的个数
package com.itheima.stream.input;

import java.io.FileInputStream;
import java.io.IOException;

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

        FileInputStream fis = new FileInputStream("F://a.txt");

        // 读取单个字节
//        int i;
//        while ( (i = fis.read()) != -1 ) {
//            System.out.println(i);
//        }

        // 读取字节数组
        byte[] bys = new byte[2];
        int len;
        while ( (len = fis.read(bys)) != -1) {
            String s = new String(bys, 0, len);
            System.out.println(s);
        }

        fis.close();
    }

	/*
        案例 : 将 f://a.txt 拷贝到 e:/ 根目录下
     */
    public void test () throws IOException {
        // 1. 创建输入流对象读取文件
        FileInputStream fis = new FileInputStream("f://a.txt");
        // 2. 创建输出流对象关联数据目的
        FileOutputStream fos = new FileOutputStream("e://b.txt");
        // 3. 读写操作
        byte[] bys = new byte[1024];
        int len;
        while ( (len = fis.read(bys)) != -1) {
            fos.write(bys,0, len);
        }
        // 4. 关流释放资源
        fis.close();
        fos.close();
    }
}

4、字节缓冲流

1)、介绍

字节缓冲流在源代码中内置了字节数组,可以提高读写效率

	构造方法
	    public BufferedInputStream(InputStream in) : 字节缓冲输入流
	    public BufferedOutputStream(OutputStream out) :  字节缓冲输出流
	
	注意:
	    缓冲流不具备读写功能, 它们只是对普通的流对象进行包装,真正和文件建立关联的, 还是普通的流对象
package com.itheima.stream.buffer;

import java.io.*;

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

        // 1. 创建字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("f://a.txt"));

        // 2. 创建字节缓冲输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("f://b.txt"));

        // 读写操作
        int len;
        byte[] bys = new byte[1024];
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bis.close();
        bos.close();
    }
}

2)、读写过程

在这里插入图片描述

3)、四种拷贝方式原理

普通流单个字节拷贝
在这里插入图片描述
普通流 + 自定义数组拷贝
在这里插入图片描述
缓冲流单个字节拷贝
在这里插入图片描述
缓冲流 + 自定义数组拷贝
在这里插入图片描述

5、FileReader 字符输入流

FileReader: 用于读取纯文本文件,解决中文乱码问题

	构造方法:
	    public FileReader(String fileName) : 字符输入流关联文件,路径以字符串形式给出
	    public FileReader(File file) : 字符输入流关联文件,路径以File对象形式给出
	
	成员方法:
	    public int read() : 读取单个字符
	    public int read(char[] cbuf) : 读取一个字符数组,返回读取到的有效字符个数
package com.itheima.stream.character.reader;

import java.io.FileReader;
import java.io.IOException;

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

        FileReader fr = new FileReader("f://a.txt");

        // 读取单个字符
//        int i;
//        while ((i = fr.read()) != -1) {
//            System.out.print((char) i);
//        }

        // 读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while ((len = fr.read(chs)) != -1) {
            String s = new String(chs, 0, len);
            System.out.println(s);
        }

        fr.close();
    }
}

6、FileWriter 字符输出流

FileWriter 字符输出流写出数据

	构造方法
	    FileWriter(String fileName) : 字符输出流关联文件,路径以字符串形式给出
	    FileWriter(String fileName, boolean append) : 参数2: 追加写入的开关
	    FileWriter(File file) : 字符输出流关联文件,路径以File对象形式给出
	    FileWriter(File file, boolean append) : 参数2: 追加写入的开关
	
	成员方法
	    public void write(int c) : 写出单个字符
	    public void write(char[] cbuf) : 写出一个字符数组
	    public write(char[] cbuf, int off, int len) : 写出字符数组的一部分
	    public void write(String str) : 写出字符串
	    public void write(String str, int off, int len) : 写出字符串的一部分
	
	注意事项: 字符输出流写出数据,需要调用flush或close方式,数据才会写出
	    flush() : 输出数据,刷出后可以继续写出
	    close() : 关闭流释放资源,顺便刷出数据,关闭后不可继续写出
package com.itheima.stream.character.writer;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo1 {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("f://c.txt");

        char[] chs = {'a', 'b', 'c'};
        fw.write(chs);
        fw.write(chs, 0, 2);
        fw.write('a');
        fw.write("你好你好~");
        fw.write("哈哈哈哈哈", 0, 2);

        fw.write("人活一世,草木一秋");
        fw.flush();

        fw.write("\r\n");
        fw.write("今晚不减肥,我要吃肉!!");
        fw.close();
    }
}

7、补充 - 字符集、字符编码

1)、字符集

字符集: 是指多个字符的集合
	GB2312字符集: 1980年发布,1981年5月1日实施的简体中文汉字编码国家标准。
		收录7445个图形字符,其中包括6763个简体汉字
		
	BIG5字符集:台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施。
	
	GBK字符集:2000年3月17日发布,收录21003个汉字。
			包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。
	        windows系统默认使用的就是GBK。
	        系统显示:ANSI
	        
	Unicode字符集:国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换

2)、字符编码

字符编码:字符编码是指一种映射规则
	根据这个规则可以将某个字符映射成其他形式的数据以便在计算机中存储和传输

GBK
	英文字符占用1个字节
	中文字符占用2个字节

UTF	Unicode Transfer Format
	UTF-16编码规则:用2-4个字节保存
	UTF-32编码规则:固定使用四个字节保存
	UTF-8编码规则:用1-4个字节保存

3)、编码解码

编码: 字符转字节
        public byte[] getBytes() : 使用平台默认字符编码方式,对字符串编码
        public byte[] getBytes(String charsetName) : 使用字符编码方式,对字符串编码

解码: 字节转字符
        public String(byte[] bytes) : 使用平台默认字符编码方式,对字符串解码
        public String(byte[] bytes, String charsetName) : 使用字符编码方式,对字符串解码

重点事项:
    中文字符,通常都是由负数的字节进行组成的
    特殊情况: 可能会出现正数,但是就算有正数,第一个字节肯定是负数
    
注意事项:
    如果出现乱码问题,大概率是因为编解码方式不一致所导致的
package com.itheima.stream.character;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class StringDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "你好,你好";
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes)); // [-28, -67, -96, -27, -91, -67, 44, -28, -67, -96, -27, -91, -67]

        byte[] gbks = s.getBytes("gbk");
        System.out.println(Arrays.toString(gbks)); // [-60, -29, -70, -61, 44, -60, -29, -70, -61]

        System.out.println("-------------------------------------");

        byte[] utf8Bytes = {-28, -67, -96, -27, -91, -67, 44, -28, -67, -96, -27, -91, -67};
        byte[] gbkBytes = {-60, -29, -70, -61, 44, -60, -29, -70, -61};
        String s1 = new String(utf8Bytes);
        String gbk = new String(gbkBytes, "gbk");
        System.out.println(s1);
        System.out.println(gbk);
    }
}

8、案例

package com.itheima.stream;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.BiConsumer;

public class Test {

    /*
        拷贝一个文件夹,考虑子文件夹
     */
    public static void main(String[] args) throws IOException {
        File src = new File("f://note");
        File dest = new File("e://");

        if (src.equals(dest)) {
            System.out.println("目标文件夹是源文件夹的子文件夹");
        } else {
            copyDir(src, dest);
        }
    }

    public static void copyDir (File src, File dest) throws IOException {
        File newDir = new File(dest, src.getName());
        newDir.mkdirs();

        // 从数据源中获取数据(File对象)
        File[] files = src.listFiles();
        // 遍历数组,获取每一个文件或文件夹对象
        for (File file : files) {
            // 判断当前对象是否是文件
            if (file.isFile()) {
                // 文件直接拷贝
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(new File(newDir, file.getName()));

                int len;
                byte[] bys = new byte[1024];
                while ( (len = fis.read(bys)) != -1) {
                    fos.write(bys, 0, len);
                }

                fis.close();
                fos.close();
            } else {
                // 文件夹,递归调用方法
                copyDir(file, newDir);
            }
        }
    }

    /*
        统计文件中每一个字符出现的次数,随后展示在控制台

        效果:
            A(1)B(2)C(3)
     */
    private static void test2() throws IOException {
        // 1. 创建map集合,用于统计每一种字符出现的次数
        HashMap<Character, Integer> map = new HashMap<>();
        // 2. 创建字符输入流读取纯文本文件
        FileReader fr = new FileReader("f://a.txt");
        // 3. 读取字符
        int i;
        while ((i = fr.read()) != -1) {
            // 4. 统计这个字符出现的次数
            if (map.containsKey((char) i)) {
                map.put((char) i, map.get((char) i) + 1);
            } else {
                map.put((char) i, 1);
            }
        }
        // 5. 关闭输入流
        fr.close();

        // 6. 打印
        StringBuilder sb = new StringBuilder();
        map.forEach(new BiConsumer<Character, Integer>() {
            @Override
            public void accept(Character key, Integer value) {
                sb.append(key).append("(").append(value).append(")");
            }
        });
        System.out.println(sb);
    }

    /*
        图片文件加密解析
            加密思路:改变原始文件中的字节,就无法打开了
                    字节 ^ 2
            解密思路:将文件中的字节还原成原始字节即可
                    字节 ^ 2
     */
    private static void test1() throws IOException {
        // 1. 创建字节输入流对象,关联要加密的图片
        FileInputStream fis = new FileInputStream("f://source//1.png");
        // 2. 创建一个容器,用来存储读取到的字节
        ArrayList<Integer> list = new ArrayList<>();
        // 3. 循环读取文件中的字节,并存入集合
        int i;
        while ((i = fis.read()) != -1) {
            list.add(i);
        }
        // 4. 关闭输入流对象
        fis.close();

        // 5. 创建输出流对象,关联图片文件
        FileOutputStream fos = new FileOutputStream("f://source//1.png");
        // 6. 遍历集合,从集合中取出字节,并写出
        for (Integer b : list) {
            fos.write(b ^ 2);
        }
        // 7. 关闭输出流对象
        fos.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值