IO流

一,文件

 1,什么是文件

  文件时保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件...都是文件。它既可以保存一张图片,也可以保存视频,声音.........

 2.文件流

   

 

 

  3.常见的文件操作

   1.创建文件对象相关构造器和方法

    

 

 

    2.创建文件的三种方式

    

public class FileCreate {
    //方式 1 new File(String pathname)
    @Test
    public void creat01(){
        String filePath = "e:\\new01.txt";
        //这里的 file 对象,在java 程序中,只是一个对象
        //只有执行了 createNewFile  方法,才会真正的,在磁盘创建该文件
        File file = new File(filePath);
        try {
            file.createNewFile();
            System.out.println("文件new01.txt创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //方式 2 new File(File parent,String child) //根据父目录文件+子路径构建
    @Test
    public void creat02(){
        File parentPath = new File("e://");
        String childPath = "new02.txt";
        File file = new File(parentPath, childPath);
        try {
            file.createNewFile();
            System.out.println("new02.txt创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //方式 3 new File(String parent,String child) //根据父目录+子路径构建
    @Test
    public void creat03(){
        String parentPath = "e:\\";
        String childPath = "new03.txt";
        File file = new File(parentPath, childPath);
        try {
            file.createNewFile();
            System.out.println("new03.txt文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  3.  获取文件的相关信息

   

 

 

     

 //获取文件信息
    @Test
    public void info(){
        //创建文件对象
        File file = new File("e:\\new01.txt");
        //调用相应的方法,获取文件信息
        System.out.println("文件名字 :" + file.getName());  //文件名字 :new01.txt
        //getName 、getAbsolutePath 、getParent 、length 、exists 、isFile 、isDirectory
        System.out.println("文件绝对路径:" + file.getAbsolutePath());  //文件绝对路径:e:\new01.txt
        System.out.println("文件父级目录 :" + file.getParent());   //文件父级目录 :e:\
        System.out.println("文件大小(字节)=" + file.length());      //文件大小(字节)=0
        System.out.println("文件是否存在=" + file.exists());//    文件是否存在=true
        System.out.println("是不是一个文件=" + file.isFile());//    是不是一个文件=true
        System.out.println("是不是一个目录=" + file.isDirectory());//   是不是一个目录=false
    }

  4. 目录的操作和文件的删除

    mkdir创建一级目录,madirs创建多级目录,delete删除空目录或文件

    

//判断文件new03.txt是否存在,存在就删除
    @Test
    public void delete01(){
        String path = "e://new03.txt";
        File file = new File(path);
        if (file.exists()){
            if (file.delete()){
                System.out.println(file + "删除成功");
            }else {
                System.out.println(file + "删除失败");
            }
        }else {
            System.out.println("文件不存在");
        }
    }
    //判断文件是否存在,存在就删除,否则提示不存在e:\\demo\\a\\b\\c判断文件new03.txt是否存在,存在就删除
    @Test
    public void mkdir01(){
        String path = "e:\\demo\\a\\b\\c";
        File filePath = new File(path);
        if (filePath.exists()){
            System.out.println(filePath + "文件存在");
        }else {
            if (filePath.mkdirs()){
                System.out.println(filePath + "创建成功");
            }else {
                System.out.println(filePath + "创建失败");
            }
        }
    }

   5, 筛选”.jpg" 文件  和 遍历e盘

    

public class File01 {   //筛选含有“.jpg"的照片
    public static void main(String[] args) throws IOException {
        File file = new File("e:/test");
        file.createNewFile();
        FilenameFilter filenameFilter = new FilenameFilter(){
            @Override
            public boolean accept(File dir, String name) {
                if (name.lastIndexOf(".jpg") == -1){
                    return false;
                }else {
                    return true;
                }
            }
        };
        String[] list = file.list(filenameFilter);
        System.out.println(Arrays.toString(list));
    }
}

 

@SuppressWarnings({"all"})
public class File02 {
    public static void main(String[] args) {
        File file = new File("e:\\");  //遍历e盘下的文件
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);  //只遍历
        }
        File[] files = file.listFiles();
        for (File file1 : files) {
            System.out.println(file1);   //带绝对路径的遍历
        }
    }
}

 

public class File02 {
    public static void main(String[] args) {
        File file = new File("e:\\test");
        String[] list = file.list();
        //遍历文件夹
        for (String str : list) {
            //找到最后一次出现“.”的位置
            int lastIndexOf = str.lastIndexOf(".");
            //截取
            String substring = str.substring(lastIndexOf);
            //比较
            if (substring.equals(".jpg")){
                System.out.println(str);
            }
        }
    }
}

 

二,IO流的原理及分类

 1. JAVA IO 流原理

      

 

       

 

  2. 流的分类  

    

 

  3.   IO 流体系图-常用的类

    

 

      文件VS流

      

 

 三,常用的类

    

 

 

 1. FileInputStream  字节输入流

      

public class FileInputSteam_ {
    @Test
    public void readFile(){
        String path = "e:\\hello.txt";
        FileInputStream inputStream = null;
        int readData = 0; //接收读出来的数据
        try {
            inputStream = new FileInputStream(path);
            //从该输入流读取一个字节的数据。  如果没有输入可用,此方法将阻止。
            //如果返回- 1 ,  表示读取完毕
            try {
                while ((readData = inputStream.read()) != -1){
                    System.out.print((char) readData);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                //关闭文件流,释放资源.
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void readFile01()  {
        String path = "e:\\hello.txt";
        byte[] buf = new byte[8]; //字节数组  一次读取8个字节
        int readData = 0;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(path);
            //从该输入流读取最多 b.length 字节的数据到字节数组。  此方法将阻塞,直到某些输入可用。 
            // 如果返回- 1 ,  表示读取完毕
            //如果读取正常,  返回实际读取的字节数
            while ((readData = inputStream.read(buf)) != -1){
                System.out.print(new String(buf,0,readData));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 2. FileOutputStream 字节输出流 

   请使用 FileOutputStream   a.txt 文件,中写入  hello ,world”

   

@Test
    public void writerFile(){
        String path = "e:\\a.txt";
        FileOutputStream outputStream = null;
        try {
    //1. new FileOutputStream(filePath)  创建方式,当写入内容是,会覆盖原来的内容
    // 2. new FileOutputStream(filePath, true)  创建方式,当写入内容是,是追加到文件后面
            outputStream = new FileOutputStream(path,true);
            try {
                //1.写入一个字节
//                outputStream.write('H');
                String str = "hello word"; ////写入字符串
                //2. 写一个字符串   //str.getBytes()  可以把 字符串->  字节数组
//                outputStream.write(str.getBytes());
                //3. write(byte[] b, int off, int len)  将 len 字节从位于偏移量 off 的指定字节数组写入此文件输出流 
                outputStream.write(str.getBytes(),0,str.length());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

     文件的拷贝 

      

@Test
    public void readWriterFile(){
        String strFile = "e:\\123.jpg"; //1.  创建文件的输入流 ,  将文件读入到程序
        String destFile = "e:\\321.jpg";//2.  创建文件的输出流,  将读取到的文件数据,写入到指定的文件.
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(strFile);
            outputStream = new FileOutputStream(destFile);
            byte[] buf = new byte[8]; //定义一个字节数组,提高读取效果
            int readLine = 0;
            try {
                while ((readLine = inputStream.read(buf)) != -1){
                    //读取到后,就写入到文件 通过 fileOutputStream
                    //即,是一边读,一边写
                    outputStream.write(buf,0,readLine); 
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if (inputStream != null){
                    inputStream.close();
                }
                if (outputStream != null){
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

3. FileReader (字符输入流)  FileWriter(字符输出流)  

  

 

 

   1).   FileReader 相关方法:

      

 

 

        

public class FileReader_ {
    @Test
    public void reader01(){  //通过单个字符读取
        String path = "e:\\hello.txt";
        FileReader reader = null;
        int readLin = 0;
        try {
            reader = new FileReader(path);
            try {
                while ((readLin = reader.read()) != -1){
                    System.out.print((char)readLin);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void reader02()  {  //第二种多个字符读取
        String path = "e:\\hello.txt";
        FileReader reader = null;
        int readLin = 0;
        char[] but = new char[8];
        try {
            //循环读取 使用 read(buf),  返回的是实际读取到的字符数
            //如果返回- 1,  说明到文件结束
            reader = new FileReader(path);
            while ((readLin = reader.read(but)) != -1){
                System.out.print(new String(but,0,readLin));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

 

 

 

    2) ,FileWriter 常用方

 

 

      

 

      

public class FileWriter_ {
    public static void main(String[] args) {
        String path = "e:\\node.txt";
        FileWriter writer = null;
        char[] chars = {'a','v','c'};
        try {
            writer = new FileWriter(path,true);
            writer.write("你好");
            writer.write("你好啊 ,好好学java".toCharArray(),0,5);
            writer.write('s');
            writer.write(chars);
            writer.write("风雨过后见彩虹",0,6);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("程序结束");
    }
}

四,节点流和处理流

  1.基本介绍

    节点流可以从一个特定的数据源读写数据,如fileReader,FileWriter

    处理流也叫包装流,是‘连接’在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader,BufferedWriter

  2. 节点流和处理流一览图

     

 

   3. 节点流和处理流的区别和联系

    

 

   4.处理流的功能主要体现在以下几个方面

    

 

   5.BufferReader 和  BufferWriter   字符包装流

    

public class BufferReader {
    public static void main(String[] args) throws Exception {
        String path = "e:\\hello.txt";
        BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
        String line;
        while ((line =bufferedReader.readLine()) != null){
            System.out.println(line);
        }
        bufferedReader.close();
    }
} 
public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        //1. new FileWriter(filePath, true)  表示以追加的方式写入
        //2. new FileWriter(filePath) ,  表示以覆盖的方式写入
        String path = "e:\\ok.txt";
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path));
        bufferedWriter.write("好好学习java");
        bufferedWriter.close();
    }
}

  字符包装流拷贝文件

  

public class BufferedCopy_ {
    public static void main(String[] args) {
        //1. BufferedReader  和 BufferedWriter  是安装字符操作
        //2.  不要去操作 二进制文件[声音,视频,doc, pdf ],  可能造成文件损坏
        String path = "e:\\hello.txt";
        String newPath = "e:\\hello01.txt";
        BufferedReader br = null;
        BufferedWriter bw = null;
        String line;
        try {
            br = new BufferedReader(new FileReader(path));
            bw = new BufferedWriter(new FileWriter(newPath));
            while ((line = br.readLine()) != null){
                //每读取一行,就写入
                bw.write(line);
                //插入一个换行
                bw.newLine();
            }
            System.out.println("拷贝完毕...");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (br != null){
                    br.close();
                }
                if (bw != null){
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  6. 字节处理流-BufferedInputStream  BufferedOutputStream

      

public class BufferedCopy02 {
    public static void main(String[] args) {
        String srcPath = "e:\\123.jpg";
        String destFilePath = "e:\\231.jpg";
        //创建 BufferedOutputStream 对象 BufferedInputStream 对象
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //因为 FileInputStream    是 InputStream  子类
            bis = new BufferedInputStream(new FileInputStream(srcPath));
            bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
            //循环的读取文件,并写入到 destFilePath
            int resLine = 0;
            byte[] bytes = new byte[1024];
            while ((resLine = bis.read(bytes)) != -1){
                bos.write(bytes,0,resLine);
            }
            System.out.println("拷贝完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null){
                    bis.close();
                }
                if (bos != null){
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  7.   对象流-ObjectInputStream  ObjectOutputStream

   1.序列化和反序列化

    1)序列化就是保存数据时,保存数据的值和数据类型

    2)反序列化就是在恢复数据时,恢复数据的值和数据类型

    3)需要让某个对象支持序列化机制,则必须让其子类时可序列化的,为了让某个类时可序列化的,该类必须实现如下两个接口之一:

      Serializable  这个是标记接口,没有方法

      Externalizable  该接口有方法需要实现,因此我们一般实现上面的Serializable接口

    

 

     2.   对象流介绍

      :提供了对基本类型或对象类型的序列化和反序列化的方法

      ObjectOutputStream  提供 序列化功能

      ObjectInputStream  提供 反序列化功能 

      

 

 

       序列化 代码

 

        

public class ObjectOutStream_ {
    public static void main(String[] args) throws Exception {
        //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
        String path = "e:\\data.dat";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        //序列化数据到 e:\data.dat
        oos.writeInt(100); // int -> Integer (实现了 Serializable)
        oos.writeDouble(9.8);// double -> Double (实现了 Serializable)
        oos.writeChar('v');// char -> Character (实现了 Serializable)
        oos.writeUTF("疾控寂痕"); //String
        oos.writeObject(new Dog("小花",18));  //保存一个 dog 对象
        oos.close();
        System.out.println("序列化完毕..............");
    }
}
//序列化的类必须实现这个接口
class Dog implements Serializable {   
    private String name;
    private int age;

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

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

    反序列化代码

    

public class ObjectInputStream_ {
    public static void main(String[] args) throws Exception {
        //指定反序列化的文件
        String path = "e:\\data.dat";
        //1.创建流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        //2.读取的顺序(反序列化)应该和你保存数据(序列化)的顺序一直
        System.out.println(ois.readInt());
        System.out.println(ois.readDouble());
        System.out.println(ois.readChar());
        System.out.println(ois.readUTF());
        System.out.println(ois.readObject());
        //3.关闭
        ois.close();
        System.out.println("反序列化完成");
    }
}

     

 

  8.   标准输入输出流

   

 

     

public class System01 {
    public static void main(String[] args) {
        //System 类里面的 public final static InputStream in = null;
        //System.in   编译类型  InputStream
        //System.in   运行类型  class java.io.BufferedInputStream
        //表示的是标准输入  键盘
        System.out.println(System.in.getClass());
        // public final static PrintStream out = null;
        // 编译类型    PrintStream
        //运行类型    class java.io.PrintStream
        //表示的是标准输出  显示器
        System.out.println(System.out.getClass());
    }
}

 9,转换流-InputStreamReader   OutputStreamWriter

   

    介绍

 

    1) InputStreamReader: Reader 的子类,可以将InputStream(字节流)包装成(转换成)Reader(字符流)

    2) OutputStreamWriter:  Writer的子类,实现将OutputStream(字节流)包装成Writer (字符流)

    3)当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换城字符流

    4) 可以在使用时指定编码格式(比如 utf-8 ,gbk , gb2312等)

     案例一:将字符流FileInputStream 包装成字符流InputStreamReader,对 文件进行读取(按照 utf-8/ gbk格式),进而在包装成BufferReader

      

public class InputStreamReader_ {
    public static void main(String[] args) throws Exception {
//        演示使用 InputStreamReader  转换流解决中文乱码问题
//       将字节流 FileInputStream  转成字符流  InputStreamReader,  指定编码 gbk/utf-8
        String path = "e:\\abc.txt";
//        //1.  把 FileInputStream  转成 InputStreamReader
//        //2.  指定编码 gbk
//        InputStreamReader isr = new InputStreamReader(new FileInputStream(path),"utf-8");
//        //3.  把 InputStreamReader  传入 BufferedReader
//        BufferedReader br = new BufferedReader(isr);
        //123合并写
        BufferedReader br = new BufferedReader(new InputStreamReader(
                                                new FileInputStream(path),"utf-8"));
        //4 读取
        String s = br.readLine();
        System.out.println(s);
        //关闭外层流
        br.close();
    }
}

    案例二 : 字节流FileOutputStream 包装成字符流OutputStreamWriter,对文件进行写入

      

public class OutputStreamWrite_ {
    public static void main(String[] args) throws Exception {
        String path = "e:\\hsp.txt";
        String charSet = "utf-8";
        // 1.创建流对象
        OutputStreamWriter osw =
                new OutputStreamWriter(new FileOutputStream("d:\\a.txt"), charSet);
        // 2.写入
        osw.write("hello,韩顺平教育~");
        // 3.关闭
        osw.close();
        System.out.println("按照" + charSet + "保存成功");
    }
}

   10, 打印流-PrintStream   PrintWriter

      1. 打印流只有输出流没有输入流

        

 

       2. PrintStream  字节输出流

        

public class PrintStream_ {  //字节输出流
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out;
        //在默认情况下,PrintStream  输出数据的位置是 标准输出,即显示器
        out.print("你好");
        //因为 print 底层使用的是 write ,  所以我们可以直接调用 write 进行打印/输出
        out.write("好好学java".getBytes());
        out.close();
        //我们可以去修改打印流输出的位置/设备
        //1.  输出修改成到 "e:\\a.txt"
        System.setOut(new PrintStream("e:\\a.txt"));
        System.out.println("好好学习  天天向上");
    }
}

     3   PrintWriter字符输出流

    

public class PrintWriter_ {
    public static void main(String[] args) throws IOException {
//        PrintWriter printWriter = new PrintWriter(System.out);//里面传的是打印的位置
        //更改写入的位置
        PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\a.txt"));
        printWriter.print("你好 北京");
        printWriter.close();
    }
}

11.   Properties 

   引入外部文件传统方式,比较麻烦  上代码

   

public class Properties01 {
    public static void main(String[] args) throws Exception {
        //读取 mysql.properties  文件,并得到 ip, user  和 pwd
        BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = br.readLine()) != null){//循环读取
            String[] split = line.split("=");
            //如果我们要求指定的 ip 值
            if("ip".equals(split[0])) {
                System.out.println(split[0] + "值是: " + split[1]);
            }
        }
        br.close();
    }
}

 

  1. 基本介绍:

    

 

     

 

     废话不多说  上代码

      

public class Properties02 {
    public static void main(String[] args) throws IOException {
        //1.  创建 Properties  对象
        Properties properties = new Properties();
        //2.  加载指定配置文件
        properties.load(new FileReader("e:\\123.properties"));
        //3.  把 k-v 显示控制台
        properties.list(System.out);
        //4.  根据 key  获取对应的值
        String user = properties.getProperty("user");
        String pwd = properties.getProperty("pwd");
        System.out.println("名字" + user + "密码" + pwd);
    }
}

    将修改保存配置文件操作

    

public class Properties03 {
    public static void main(String[] args) throws Exception {
        //使用 Properties  类来创建 配置文件,  修改配置文件内容
        Properties properties = new Properties();
        //创建
        //1.如果该文件没有 key  就是创建
        //2.如果该文件有 key ,就是修改
        properties.setProperty("name","博文");////注意保存时,是中文的 unicode 码值
        properties.setProperty("age","28");
        properties.setProperty("user","123456");
        //将k-v  存储文件中即可
        properties.store(new FileOutputStream("e:\\123.properties"),null);
        System.out.println("文件配置成功");
    }
}

 

 

无论是那种流, 用完之后都需要关闭 close掉

垃圾回收器(GC garbage collector) 只能回收纯内存资源
但是流对象 的堆内存中 有一部分是指向本地操作系统的文件的
如果这个链接不断开
那么对象地址断开了 也不会变成垃圾对象
因为堆内存的流对象依然针对本地文件有链接操作

不同操作系统有对应的换行符

windows里面的换行符号是 \r\n
linux操作系统是 \n
macos操作系统是 \r

 

注意:

      字节是指当前数据在计算机内存中所占的空间

      字符是指 一个汉字或者一个字母 都算是一个字符
      由于Idea开发工具的原因 目前我们使用的编码是UTF-8(后面讲)
      UTF-8编码下 一个汉字占3个字节 一个字母占1个字节

      注意: 如果关联的文件不存在则自动创建, 路径不存在则报错.

 

//输出     好java    一个汉字三个字节   你好java 
//        ops.write("你好java".getBytes(),3,6);ops.close();

 

   

/*
编码表
由字符及其对应的数值组成的一张表
常见编码表
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:国标, 中国的中文编码表。
GBK(相对其他两个用的比较多):中国的中文编码表升级,融合了更多的中文文字符号。 一个汉字用两个字节存储
GB18030:GBK的取代版本

BIG-5码 :通行于台湾省、香港地区的一个繁体字编码方案,俗称“大五码”。

Unicode:国际标准码,融合了多种文字。 相对其他的编码, 一个符号占用的字节往往要更多一点
所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8(所有编码中目前用的最多的):最多用三个字节来表示一个字符。 各取所长, 一个汉字三个字节, 一个字母一个字节


编码
把看得懂的变成看不懂的 字符串 -> byte数组
解码
把看不懂的变成看得懂的 byte数组 -> 字符串
乱码:
1.编码与解码中间 码表发生了切换 字符串编码解码的时候会说到
2.漏了一些字节
3.使用不支持这个字符的编码表

字符串编码与解码
注意: 如果本身这个编码表就不支持中文, 强行用这种编码表编码中文, 也会出现乱码问题
注意: 只要是编码或者解码, 只要是把能看懂的变成看不懂的, 就一定是参照了某种编码表的

 

   

 

  

           

posted @ 2022-12-08 22:06  阿文程序猿  阅读(44)  评论(0)    收藏  举报