IO流学习笔记

目录

1.流的概念

  • 流:内存与存储设备之间传输数据的通道

img

2.流的分类

2.1 按流向分类

  • 输入流:将<存储设备>中的内容读到<内存>中
  • 输出流:将<内存>中的内容写到<存储设备>中

2.2 按单位分类

  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位,只能读写文本数据

2.3 按功能分类

  • 节点流:具有实际传输数据的读写功能
  • 过滤流:在节点流的基础之上增强功能

3.字节流

字节流的父类(抽象类)

//InputStream 字节输入流
public int read(){}
public int read(byte[] b){}
public int read(byte[] b, int off, int len){}

// OutputStream 字节输出流
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b, int off, int len){}

3.1文件字节流

FileInputStream entends InputStream:
public int read(byte[] b)//从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1。
FileOutputStream entends OutputStream:
public void write(byte[] b)//一次写多个字节,将b数组中所有字节,写入输出流。

/**
 * 演示FileInputStream的使用
 */

public class Demo01 {
    public static void main(String[] args) throws Exception{
        // 1 创建FileInputStream 并指定文件路径
        FileInputStream fis = new FileInputStream("d:\\aaa.txt");//abcdefg
        // 2 读取文件
        // fis.read();
        // 2.1单字节读取
//        System.out.println("==========单字节读取=========");
//        int data = 0;
//        while((data = fis.read()) != -1){
//            System.out.print(((char) data));//read():返回读到的的字节(ASCII编码形式),读到结尾返回-1
//        }//执行完以上代码,read()方法中指针已到达文件结尾
//        System.out.println();
        // 2.2 一次读取多个字节
        System.out.println("==========一次读取多个字节=========");
        byte[] buf = new byte[3]; // 建立大小为3的字节数组
//        int count = fis.read(buf); // read(Byte[] byte):一次读3个字节,并将读到的字节存储到byte[]中,并返回读取的个数
//        String str=new String(buf);//new String(Bytr[] byte):把byte中的字节转为字符串
//        System.out.println(str);//输出abc
//        System.out.println(count);//输出3
//        int count1 = fis.read(buf); // 再读3个
//        System.out.println(new String(buf));//输出def
//        System.out.println(count1);
//        int count2 = fis.read(buf);//返回读取的个数
//        System.out.println(new String(buf));//输出gef
//        System.out.println(count2);//输出1,此时读取了1个字节
//        int count3 = fis.read(buf);//返回读取的个数
//        System.out.println(count3);//输出-1,此时指针到达末尾
        // 上述代码有些冗长,进行优化
        int count = 0;
        while((count = fis.read(buf)) != -1){
            System.out.println((new String(buf, 0, count)));//把buf中下标从0到(count-1)的字节转换为字符串
        }
        // 3 关闭
        fis.close();
        System.out.println("执行完毕");
    }
}

/**
 * 演示文件字节输出流的使用
 * FileOutPutStream
 */
public class Demo02 {
    public static void main(String[] args) throws Exception{
        //1.创建一个FileOutPutStream对象
        FileOutputStream fos = new FileOutputStream("d:\\bbb.txt");
//        FileOutputStream fos = new FileOutputStream("d:\\bbb.txt",true);
//        这种方法可以不覆盖源文件,在源文件后面追加
        //2.写入文件
        fos.write(97);//写入的是ASCII码
        fos.write('b');
        fos.write('c');
        String str="Hello World";
        fos.write(str.getBytes());//getBytes():获取字符串对应的字节数组
        //3.关闭
        fos.close();
        System.out.println("执行完毕");
    }
}

/**
 * 使用文件字节流实现文件的复制
 */
public class Demo03 {
    public static void main(String[] args) throws Exception{
        //1.创建流
        //1.1文件字节输入流
        FileInputStream fis=new FileInputStream("d:\\001.jpg");
        //1.2文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\002.jpg");
        //2.边读边写
        byte[] buf=new byte[1024];
        int count=0;
        count=fis.read(buf);
        int i=0;
        while ((count=fis.read(buf))!=-1){
            fos.write(buf,0,count);
            i++;
        }
        System.out.println(i);
        fis.close();
        fos.close();
        System.out.println("执行完毕");
    }
}

3.2字节缓冲流

  • 缓冲流:BufferedInputStream/BufferedOutputStream。
    • 提高IO效率,减少访问磁盘的次数;
    • 数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close。
/**
 * 使用字节缓冲流读取
 * BufferedInputStream
 * @author NG
 */
public class Demo04 {
    public static void main(String[] args) throws Exception{
        //1.创建BufferedInputStream
        FileInputStream fis=new FileInputStream("d:\\aaa.txt");
        BufferedInputStream bis=new BufferedInputStream(fis);
        //2.读取
//        int date=0;
//        while ((date=bis.read())!=-1){//bis实际上创建了一个大小为8k的缓冲区,先把数据读到了缓冲区
//            System.out.print((char) date);
//        }
        byte[] bytes=new byte[1024];
        int count=0;
        while ((count=fis.read(bytes))!=-1);{
            System.out.println(new String(bytes,0,count));
        }
        //3.关闭
        bis.close();
    }
}

/**
 * 使用字节缓冲流输出
 * BufferedOutputStream
 * @author NG
 */
public class Demo05 {
    public static void main(String[] args) throws Exception{
        //1.创建字节输出缓冲流
        FileOutputStream fos=new FileOutputStream("d:\\buffer.txt");
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        //2.写入文件
        for (int i = 0; i <10 ; i++) {
            bos.write("HelloWorld\r\n".getBytes());//写入了8k的缓冲区,没有写入硬盘
            bos.flush();//刷新到硬盘
        }
        //3.关闭
        bos.close();//内部会调用fos.close()
    }
}

3.3对象流

  • 对象流:ObjectOutputStream/ObjectInputStream

    • 增强了缓冲区功能

    • 增强了读写8种基本数据类型和字符串功能

    • 增强了读写对象的功能:

      readObject()//从流中读取一个对象
      writeObject(0bject obj)//向流中写入一个对象
      
      
  • 使用流传输对象的过程称为序列化、反序列化。

/**
 *使用ObjectOutputStream实现对象的序列化
 * 要实现序列化的类必须实现Serializable接口
 */
public class Demo06 {
    public static void main(String[] args) throws Exception{
        //1.创建对象流
        FileOutputStream fos=new FileOutputStream("d:\\JavaStream\\stu.bin");
        ObjectOutputStream oos=new ObjectOutputStream(fos);
        //2.实现序列化(写入操作)
        Student student = new Student("张三",20);
        oos.writeObject(student);
        //3.关闭
        oos.close();
        System.out.println("序列化完毕");
    }
}

/**
 * 使用ObjectInputStream实现对象的反序列化(读取重构成对象)
 * 要实现序列化的类必须实现Serializable接口
 */
public class Demo07 {
    public static void main(String[] args) throws Exception{
        //1.创建对象流
        FileInputStream fis=new FileInputStream("d:\\JavaStream\\stu.bin");
        ObjectInputStream ois=new ObjectInputStream(fis);
        //2.反序列化(读取文件)
        Student s=(Student)ois.readObject();
        //3关闭
        ois.close();//内部会关闭fis
        System.out.println(s.toString());
    }

  • 对象流注意事项
/**
 *使用ObjectOutputStream实现对象的序列化
 * 注意事项:
 * (1)要实现序列化的类必须实现Serializable接口
 * (2)要实现序列化的类中对象属性必须实现Serializable接口
 *  (比如学生类中有一个由类创建的属性,那么这个类也要实现Serializable接口)
 * (3)序列化版本ID,保证序列化和反序列化的类是同一个类
 * (4)使用transient修饰符修饰属性,那么这个属性就不能序列化了
 * (5)静态属性不能序列化
 * (6)序列化多个对象,可以借助集合来实现
 */
public class Demo06 {
    public static void main(String[] args) throws Exception{
        //1.创建对象流
        FileOutputStream fos=new FileOutputStream("d:\\JavaStream\\stu.bin");
        ObjectOutputStream oos=new ObjectOutputStream(fos);
        //2.实现序列化(写入操作)
        Student student = new Student("张三",20);
        Student student1 = new Student("李四",22);
        ArrayList<Student> arrayList=new ArrayList<>();
        arrayList.add(student);
        arrayList.add(student1);
        oos.writeObject(arrayList);
        //3.关闭
        oos.close();
        System.out.println("序列化完毕");
    }

/**
 * 使用ObjectInputStream实现对象的反序列化(读取重构成对象)
 * 要实现序列化的类必须实现Serializable接口
 */
public class Demo07 {
    public static void main(String[] args) throws Exception{
        //1.创建对象流
        FileInputStream fis=new FileInputStream("d:\\JavaStream\\stu.bin");
        ObjectInputStream ois=new ObjectInputStream(fis);
        //2.反序列化(读取文件)
        ArrayList<Student> list= (ArrayList<Student>) ois.readObject();
        //3关闭
        ois.close();//内部会关闭fis
        System.out.println(list.toString());
    }
}

/**
 * 学生类
 */
public class Student implements Serializable {
//把鼠标放到需要添加序列号的类名上,Alt + Enter快速生成SerializableUID
    private static final long serialVersionUID = -441706825686703656L;
    private String name;
    private transient int age;//transient修饰符修饰的属性不能序列化
    public static String country="中国";//静态属性不能序列化

    public Student() {
    }

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

    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;
    }

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

4.字符流

  • 常见字符编码:

    • ISO-8859-1:收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。

    • UTF-8:针对Unicode码表的可变长度字符编码(1个字节,或者两个字节,对于中文是三个字节)

    • GB2312:简体中文(1个字节,或者两个字节)

    • GBK:简体中文、扩充(1个字节,或者两个字节)

    • BIG5:台湾,繁体中文

  • 当编码方式和解码方式不一致时,会出现乱码。

  • 字符流的父类(抽象类):Reader和Writer

//Reader:字符输入流
//Reader中的方法:
public int read() {}
public int read(char[]c){}
public int read (char[] b, int off,int len){}

//Writer:字符输入流
//Writer中的方法:
public void write(int n){}
public void write(String str){}
public void write(ehar[] c){}

4.1文件字符流

//FileReader:
 public int read(char[] c)//从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回-1

//FileWriter:
 public void write(String str)//一次写多个字符,将b数组中所有字符,写入输出流。

/**
 * 使用FileReader来读取文件
 */
public class Demo02 {
    public static void main(String[] args) throws Exception{
        //1.创建文件字符输入流
        FileReader fr=new FileReader("d:\\JavaStream\\hello.txt");
        //2.读取文件
        //2.1单个字符读取
//        int count;
//        while ((count=fr.read())!=-1){//每次读取一个字符,如果是汉字就读取三个字节
//            System.out.print((char) count);
//        }
        //2.2多个字符读取
        char[] chars=new char[1024];
        int count;
        while ((count=fr.read(chars))!=-1){
            System.out.println(new String(chars,0,count));
        }
        //3.关闭
        fr.close();
    }
}

/**
 * 使用FileWriter来输出文件
 */
public class Demo03 {
    public static void main(String[] args) throws Exception{
        //1.创建文件字符输出流
        FileWriter fw=new FileWriter("d:\\JavaStream\\write.txt");
        //2.输出文件
        for (int i=0;i<10;i++) {
            fw.write("Java是世界上最好的语言\n");
        }
        //3.关闭
        fw.close();
    }
}

/**
 * 使用文件字符流来实现文件的复制,只能复制文本文件,不能复制图片,音频等二进制文件
 */
public class Demo04 {
    public static void main(String[] args) throws Exception{
        FileReader fr=new FileReader("d:\\JavaStream\\write.txt");
        FileWriter fw=new FileWriter("d:\\JavaStream\\write111.txt");
        int count;
        char[] chars=new char[1024];
        while ((count=fr.read(chars))!=-1){
            fw.write(chars,0,count);
        }
        fr.close();
        fw.close();
        System.out.println("复制完毕");
    }
}

4.2字符缓冲流

  • 缓冲流: BufferedReader/BufferedWriter

    • 高效读写
    • 支持输入换行符。
    • 可一次写一行、读一行。
    /**
     * 使用字符缓冲流读取文件
     * BufferedReader
     */
    public class Demo05 {
        public static void main(String[] args) throws Exception{
            //1.创建缓冲流
            FileReader fr=new FileReader("d:\\JavaStream\\write.txt");
            BufferedReader br=new BufferedReader(fr);
            //2.读取
            //2.1 创建缓冲区读取
    //        char[] buf=new char[1024];
    //        int count;
    //        while ((count=br.read(buf))!=-1){
    //            System.out.println(new String(buf,0,count));
    //        }
    //        for (int i = 0; i < 13; i++) {
    //            System.out.println(buf[i]);
    //        }
            //2.2 一行一行的读取
    
            String str=null;
            while((str=br.readLine())!=null) {
                //reafLine():读取一行,以String形式返回这一行的内容,读到结束返回null
                System.out.println(str);
            }
            //3.关闭
            br.close();
        }
    }
    
    
    /**
     * 演示BufferedWriter的使用
     *
     */
    public class Demo06 {
        public static void main(String[] args) throws Exception{
            //1.创建BufferedWriter对象
            FileWriter fw=new FileWriter("d:\\JavaStream\\buffer.txt");
            BufferedWriter bw=new BufferedWriter(fw);
            //2.写入
            for (int i = 0; i < 10; i++) {
                bw.write("好好学习,天天向上");
                bw.newLine();//写入一个换行符\r\n
                bw.flush();
            }
            //3.关闭
            bw.close();
            System.out.println("执行完毕");
        }
    }
    
    

4.3打印流

  • PrintWriter:
    • 封装了print() / println()方法,支持写入后换行
    • 支持数据原样打印
/**
 * 演示PrintWriter的使用
 */
public class Demo07 {
    public static void main(String[] args) throws Exception{
        //1.创建打印流
        PrintWriter pw=new PrintWriter("d:\\JavaStream\\print.txt");
        //2.打印
        pw.println(97);
        pw.println(true);
        pw.println(3.14);
        pw.print('a');
        //3.关闭
        pw.close();//关闭时自动执行flush()
        System.out.println("执行完毕");
    }
}

5.转换流

  • 桥转换流:InputStreamReader/OutputStreamWriter。
    • 可将字节流转换为字符流。
    • 可设置字符的编码方式。
/**
 * 演示InputStreamReader的使用
 */
public class Demo08 {
    public static void main(String[] args) throws Exception{
        //1.创建InputStreamReader对象
        FileInputStream fis=new FileInputStream("d:\\JavaStream\\write.txt");
        InputStreamReader isr=new InputStreamReader(fis,"utf-8");
        //2.读取文件
        int data=0;
        while ((data=isr.read())!=-1){
            System.out.print((char)data);
        }
        //3.关闭
        isr.close();
    }
}

/**
 * 使用OutputStreamWriter写入文件,使用指定的编码
 */
public class Demo09 {
    public static void main(String[] args) throws Exception{
        //1.创建OutputStreamWriter对象
        FileOutputStream fos=new FileOutputStream("d:\\JavaStream\\info.txt");
        OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk");
        //2.写入
        for (int i = 0; i < 10; i++) {
            osw.write("我爱北京,我爱故乡\r\n");
            osw.flush();
        }
        //3.关闭
        osw.close();
    }
}

6.File类

  • 概念:代表物理盘符中的一个文件或者文件夹。
  • 方法:
createNewFile()//创建一个新文件. 
mkdir()//创建一个新目录
delete( //删除文件或空日录
exists()//判断File对象所代表的对象是否存在
getAbsolutePath)//获取文件的绝对路径
getName 0)//取得名字
getParent 0 //获取文件/目录所在的目录
isDirectory () //是否是日录
isFile()//是否是文件
length()//获得文件的长度
listFiles()//列出目录中的所有内容
renameTo()//修改文件名为

/**
 * 演示File类的使用
 * (1)分隔符
 * (2)文件操作
 * (3)文件夹操作
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        seperator();
        fileOpe();
        directoryOpe();
    }
    //(1)分隔符
    public static void seperator(){
        System.out.println("路径分隔符"+ File.pathSeparator);
        System.out.println("名称分隔符"+ File.separator);
    }
    //(2)文件操作
    public static void fileOpe() throws Exception{
        System.out.println("==========文件操作=============");
        //1.创建文件
        File file=new File("d:\\JavaStream\\file.txt");//此时文件还不存在,只是创建了一个文件对象
        //System.out.println(file.toString());
        if (!file.exists()) {//file.exists():判断文件是否存在,存在返回true,否则false
            boolean bool = file.createNewFile();//创建文件,创建成功返回true;创建成功以后再次创建返回false
            System.out.println("创建结果:" + bool);
        }
        //2.删除文件
        //2.1 直接删除
//        System.out.println("删除结果:"+file.delete());//file.delete():删除文件,删除成功返回true,否则false
        //2.2 使用JVM退出时删除
//        file.deleteOnExit();//JVM退出时删除文件
//        Thread.sleep(5000);//休眠5s

        //3.获取文件信息
        System.out.println("获取文件的绝对路径:"+file.getAbsolutePath());
        System.out.println("获取路径:"+file.getPath());
        System.out.println("获取名称:"+file.getName());
        System.out.println("获取父目录:"+file.getParent());
        System.out.println("获取文件长度:"+file.length());
        System.out.println("获取文件创建时间:"+new Date(file.lastModified()).toLocaleString());

        //4.判断
        System.out.println("是否可写:"+file.canWrite());
        System.out.println("是否是文件:"+file.isFile());
        System.out.println("是否隐藏:"+file.isHidden());
    }
    //(3)文件夹操作
    public static void directoryOpe() throws Exception{
        System.out.println("==========文件夹操作=============");
        //1.创建文件夹
        File dir=new File("d:\\JavaStream\\aaa\\bbb");
//        System.out.println(dir.toString());//此时并没有创建文件夹
        while (!dir.exists()){
            //dir.mkdir();//只能创建单级目录,本案例是多级目录
            System.out.println("创建结果:"+dir.mkdirs());//创建成功返回true,否则false
        }
        //2.删除文件夹
//        //2.1直接删除
//        System.out.println("删除结果"+dir.delete());
//        //删除文件夹:只能删除最底层目录,并且只有文件夹为空文件夹时才能删除成功
//        //2.2使用JVM删除
//        dir.deleteOnExit();
//        Thread.sleep(5000);
        //3.获取文件夹信息
        System.out.println("获取绝对路径:"+dir.getAbsolutePath());
        System.out.println("获取路径:"+dir.getPath());
        System.out.println("获取文件夹名称:"+dir.getName());//只能获得底下层目录的名称
        System.out.println("获取父目录:"+dir.getParent());
        System.out.println("获取创建时间:"+new Date(dir.lastModified()).toLocaleString());
        //4.判断
        System.out.println("判断是否是文件夹:"+dir.isDirectory());
        System.out.println("判断是否隐藏:"+dir.isHidden());
        //5.遍历文件夹
        File dir2=new File("d:\\JavaCode");
        String[] files=dir2.list();//遍历使用list()或者listFile(),list()返回字符串数组,listFile()返回File数组
        System.out.println("==================");
        for (String s:files){
            System.out.println(s);
        }
    }
}

7.FileFilter接口

public interface FileFilter{
     boolean accept(File pathname)}

  • 当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,对获取文件进行过滤,只有满足条件的文件的才可出现在listFiles()的返回值中。
/**
 * 演示FileFilter接口的使用
 */
public class Demo02 {
    public static void main(String[] args) throws Exception{
        directoryOpe();
    }
    public static void directoryOpe() throws Exception{
        File dir=new File("C:\\Users\\15924\\Desktop\\党建德育助理\\2021.3");
        File[] files=dir.listFiles(new FileFilter() {//使用匿名内部类可以简化代码
            @Override
            public boolean accept(File pathname) {
                if(pathname.getName().endsWith(".xls")){
                    return true;
                }
                return false;
            }
        });
        for(File file:files){
            System.out.println(file.getName());
        }
    }
}

public class Demo02 implements FileFilter{
    public static void main(String[] args) throws Exception{
        directoryOpe();
    }
    public static void directoryOpe() throws Exception{

        File dir=new File("C:\\Users\\15924\\Desktop\\党建德育助理\\2021.3");
        FileFilter ff=new Demo02();
        File[] files = dir.listFiles(ff);
        for(File file:files){
            System.out.println(file.getName());
        }
    }
    @Override
    public boolean accept(File pathname) {
        if(pathname.getName().endsWith(".xls")){
                    return true;
                }
                return false;
    }
}

/**
 * 递归遍历文件夹和递归删除文件夹
 */
public class Demo03 {
    public static void main(String[] args) {
        listDir(new File("C:\\Users\\15924\\Desktop\\myfiles"));
        deleteDir(new File("C:\\Users\\15924\\Desktop\\myfiles"));

    }
    //案例1:递归遍历文件夹
    public static void listDir(File dir){
        File[] files=dir.listFiles();
        if(files!=null&&files.length>0){
            for(File file:files){
                if(file.isDirectory()){
                    System.out.println(file.getAbsolutePath());
                    listDir(file);
                }
                if(file.isFile()){
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
    }
    //案例1:递归删除文件夹
    public static void deleteDir(File dir){
        File[] files=dir.listFiles();
        if (files!=null&&files.length>0){
            for(File file:files){
                if(file.isDirectory()){
                    deleteDir(file);
                }else{
                    System.out.println(file.getAbsolutePath()+"删除"+file.delete());
                }
            }
        }
        System.out.println(dir.getAbsolutePath()+"删除"+dir.delete());
    }
}

8.Properties集合

  • Properties:属性集合
  • 特点:
    • 1存储属性名和属性值
    • 2属性名和属性值都是字符串类型
    • 3 没有泛型
    • 4和流有关
/**
 * 演示Properties的使用
 */
public class Demo01 {
    public static void main(String[] args) throws Exception{
        //1.创建一个Properties集合
        Properties properties=new Properties();
        //2.添加数据
        properties.setProperty("username", "zhangsan");
        properties.setProperty("age", "20");
        System.out.println(properties.toString());
        //3.遍历
        //3.1 ------keySet()------
        System.out.println("=========keySet()=========");
        Set<Object> set=properties.keySet();
        for (Object o : set) {
            System.out.println( o+"="+properties.get(o));
        }
        //3.2 ------entrySet()------
        System.out.println("=========entrySet()=========");
        Set entryset=properties.entrySet();
        for (Object o : entryset) {
            System.out.println(o);
        }
        //3.3 ------stringPropertyNames()------
        System.out.println("=========stringPropertyNames()=========");
        Set<String> pronames=properties.stringPropertyNames();
        for (String proname : pronames) {
            System.out.println(proname+"="+properties.getProperty(proname));
        }
        //4.和流有关的方法
        //------list()方法------
        PrintWriter pw=new PrintWriter("d:\\print.txt");
        properties.list(pw);
        pw.close();
        //------store()方法------
        FileOutputStream fos=new FileOutputStream("d:\\store.properties");
        properties.store(fos,"注释");//store()方法不允许出现中文,存储过程中会进行转码
        fos.close();
        //------load()方法------
        Properties properties1=new Properties();
        FileInputStream fis=new FileInputStream("d:\\store.properties");
        properties1.load(fis);
        fis.close();
        System.out.println(properties1.toString());
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值