黑马20天学会Java(File、递归、IO流)详细笔记

1 File类的使用

2 方法递归

3 字符集

3.1 常见字符集介绍

3.1.1 ASCII字符集

  • ASCII使用1个字节存储一个字符,一个字节是8位
  • 包括了数字、英文、符号
    在这里插入图片描述

3.1.2 GBK

  • GBK是中国的码表,包含了几万个汉字等字符,同时也要兼容ASCII编码
  • GBK编码中一个中文字符一般以两个字节的形式存储。

3.1.3 Unicode

  • 统一码,也叫万国码
  • UTF-8是Unicode的一种常见编码方式。
  • UTF-8编码后一个中文一般以三个字节的形式存储,同时也要兼容ASCII编码表。

字符解码时使用的字符集和编码时使用的字符集必须一致,否则会出现乱码
英文和数字在任何国家的编码中都不会乱码

3.2 字符集的编码、解码操作

  • String编码
    在这里插入图片描述
  • String解码
    在这里插入图片描述
package com.itheima.d3_charset;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1、编码:把文字转换成字节(使用指定的编码)
        String name = "abc我爱你中国";
        // 1.1 以当前代码默认字符集进行编码 (UTF-8)
        byte[] bytes_utf = name.getBytes();
        System.out.println("bytes_utf.length = " + bytes_utf.length);// 18
        // [97, 98, 99, -26, -120, -111, -25, -120, -79, -28, -67, -96, -28, -72, -83, -27, -101, -67]
        System.out.println("Arrays.toString(bytes_utf) = " + Arrays.toString(bytes_utf));

        // 1.2 指定编码
        byte[] bytes_gbk = name.getBytes("GBK");
        System.out.println("bytes_gbk.length = " + bytes_gbk.length);// 13
        // [97, 98, 99, -50, -46, -80, -82, -60, -29, -42, -48, -71, -6]
        System.out.println("Arrays.toString(bytes_gbk) = " + Arrays.toString(bytes_gbk));

        // 2、解码:把字节转换成对应的中文形式(编码前 和 编码后的字符集必须一致,否则乱码 )
        // 2.1 UTF-8
        String rs_utf = new String(bytes_utf); // 默认的UTF-8
        System.out.println("rs_utf = " + rs_utf);// abc我爱你中国

        // 2.2 GBK
        String rs_gbk = new String(bytes_gbk, "GBK"); // 指定GBK解码
        System.out.println("rs_gbk = " + rs_gbk);// abc我爱你中国

    }
}

4 IO流

4.1 IO流概述

在这里插入图片描述

4.2 字节流

  • 使用文件字节输入流每次读取一个字节数组的数据
  • 相对路径是相对当前工程名的,从src开始即可
  • 小技巧
System.out.println(len3); // 两次输出之间换行
System.out.print(len3); // 两次输出之间不换行

4.2.1 字节输入流:每次读取一个字节数组

  • 会出现乱码现象
  • 如果文件过大,定义的字节数组可能引起内存溢出
package com.itheima.d4_byte_stream;
import java.io.FileInputStream;
import java.io.InputStream;
/**
   目标:使用文件字节输入流每次读取一个字节数组的数据。
 */
public class FileInputStreamDemo02 {
    public static void main(String[] args) throws Exception {
        // 1 创建一个文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("src\\com\\itheima\\data.txt");

        // 2 改进使用循环,每次读取一个字节数组
        byte[] buffer = new byte[3];
        int len; // 记录每次读取的字节数。
        while ((len = is.read(buffer)) != -1) {
            // 读取完毕返回-1
            // 读取多少倒出多少
            // 输出:ab3爱哈哈哈哈哈哈哈哈哈哈  
            // 这里是不会换行的
            System.out.print(new String(buffer, 0 , len));
        }
    }
}

4.2.2 字节输入流:读取文件的全部字节

  • 不会出现乱码现象
  • 如果文件过大,定义的字节数组可能引起内存溢出
package com.itheima.d4_byte_stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class FileInputStreamDemo03 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输入流管道与源文件接通
        File f = new File("src\\com\\itheima\\data.txt");
        InputStream is = new FileInputStream(f);

        // 2.1 定义一个字节数组与文件的大小刚刚一样大。
        byte[] buffer = new byte[(int) f.length()];
        int len = is.read(buffer);
        // 读取了多少个字节:36
        System.out.println("读取了多少个字节:" + len);
        // 文件大小:36
        System.out.println("文件大小:" + f.length());
        // 输出:ab3爱哈哈哈哈哈哈哈哈哈哈
        System.out.println(new String(buffer));

        // 2.2 官方为字节输入流InputStream提供了如下API
        // 读取全部字节数组
        byte[] buffer2 = is.readAllBytes();
        // 字节转化为String
        // 输出:ab3爱哈哈哈哈哈哈哈哈哈哈
        System.out.println(new String(buffer2));
    }
}

4.2.3 字节输出流:写字节数据到文件

package com.itheima.d4_byte_stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class OutputStreamDemo04 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个文件字节输出流管道与目标文件接通
        // 第二次写的时候,不用清空原来的数据 追加数据管道
        OutputStream os = new FileOutputStream("src/com/itheima/data02.txt" , true);
        // 先清空之前的数据,写新数据进入
        // OutputStream os1 = new FileOutputStream("src/com/itheima/data02.txt");

        // 2、写数据出去
        // 2.1 写一个字节出去
        // 可以写具体的字符
        os.write('a');
        // 可以写ASCILL的编码
        os.write(98);
        // 不可以直接写中文字符  会乱码 一定要注意
        os.write('徐');
        // 实现写出换行
        os.write("\r\n".getBytes()); // 换行


        // 2.2 写一个字节数组出去。
        byte[] buffer = {'a' , 97, 98, 99};
        os.write(buffer);
        os.write("\r\n".getBytes()); // 换行

        byte[] buffer2 = "我是中国人".getBytes();
        os.write(buffer2);
        os.write("\r\n".getBytes()); // 换行


        // 2.3 写一个字节数组的一部分出去。
        byte[] buffer3 = {'a',97, 98, 99};
        os.write(buffer3, 0 , 3);
        os.write("\r\n".getBytes()); // 换行

        // 写出去的数据能成功生效  这个必须加
        // os.flush(); // 写数据必须,刷新数据 可以继续使用流
        os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用了
    }
}

4.2.4 文件拷贝

  • 学会使用字节流完成文件的复制(支持一切文件类型的复制)
package com.itheima.d4_byte_stream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyDemo05 {
    public static void main(String[] args) {
        try {
            // 1、创建一个字节输入流管道与原视频接通
            InputStream is = new FileInputStream("src/com/itheima/data03.txt");

            // 2、创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("src/com/itheima/data06.txt");

            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

            // 4、关闭流。
            os.close();
            is.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

4.3 资源释放的方式

4.3.1 基本做法(try-catch-finally)

package com.itheima.d5_resource;
import java.io.*;

public class TryCatchFinallyDemo1 {
    public static void main(String[] args) {
        
        // 资源的定义要写在外面 不然finally里面获取不到
        InputStream is = null;
        OutputStream os = null;
        try {

            // System.out.println(10/ 0);

            // 1、创建一个字节输入流管道与原视频接通
             is = new FileInputStream("file-io-app/src/out04.txt");

            // 2、创建一个字节输出流管道与目标文件接通
             os = new FileOutputStream("file-io-app/src/out05.txt");

            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

         //   System.out.println( 10 / 0);

        } catch (Exception e){
            // 只有发生了异常 才会执行到这条代码
            e.printStackTrace();
        } finally {
            // 无论代码是正常结束,还是出现异常都要最后执行这里
            System.out.println("========finally=========");
            // 里面的资源还是要try  catch
            // 判断非空之后才可以关闭
            try {
                // 4、关闭流。
                if(os!=null)os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4.3.2 JDK7改进方案(try-with-resource)(推荐使用)

package com.itheima.d5_resource;

import java.io.*;
public class TryCatchResouceDemo2 {
    public static void main(String[] args) {

        try (
                // 这里面只能放置资源对象,用完会自动关闭:
                // 自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
                // 1、创建一个字节输入流管道与原视频接通
               InputStream is = new FileInputStream("file-io-app/src/out04.txt");
                // 2、创建一个字节输出流管道与目标文件接通
               OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
                ) {

            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

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

5 字符流

5.1 字符输入流- 一次读取一个字符数组

  • 读取的性能得到了提升
  • 读取中文字符不会出现乱码
package com.itheima.d6_char_stream;
import java.io.FileReader;
import java.io.Reader;

public class FileReaderDemo02 {
    public static void main(String[] args) throws Exception {

        // 1、创建一个文件字符输入流与源文件接通
        Reader fr = new FileReader("file-io-app/src/data07.txt");

        // 2、用循环,每次读取一个字符数组的数据。  1024 + 1024 + 8
        char[] buffer = new char[1024]; // 1K字符
        int len;
        while ((len = fr.read(buffer)) != -1) {
            String rs = new String(buffer, 0, len);
            System.out.print(rs);
        }

    }
}

5.2 字符输出流

package com.itheima.d6_char_stream;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Arrays;

public class FileWriterDemo03 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        // 覆盖管道,每次启动都会清空文件之前的数据
        // Writer fw1 = new FileWriter("src/com/itheima/out08.txt");
        // 可追加数据
        Writer fw = new FileWriter("src/com/itheima/out08.txt", true);

        // 2.1 写一个字符出去
        fw.write(98);
        fw.write('a');
        fw.write('徐'); // 不会出问题了
        fw.write("\r\n"); // 换行

        // 2.2 写一个字符串出去
        fw.write("abc我是中国人");
        fw.write("\r\n"); // 换行


        // 2.3 写一个字符数组出去

        // 将字符串转化为字符数组
        char[] chars = "abc我是中国人".toCharArray();
        // chars = [a, b, c, 我, 是, 中, 国, 人]
        System.out.println("chars = " + Arrays.toString(chars));

        fw.write(chars);
        fw.write("\r\n"); // 换行


        // 2.4 写字符串的一部分出去
        fw.write("abc我是中国人", 0, 5);
        fw.write("\r\n"); // 换行


        // 2.5 写字符数组的一部分出去
        fw.write(chars, 3, 5);
        fw.write("\r\n"); // 换行


        // fw.flush();// 刷新后流可以继续使用
        fw.close(); // 关闭包含刷线,关闭后流不能使用

    }
}

6 缓冲流

6.1 缓冲流概述、字节缓冲流的使用

  • 缓冲流也称为高效流、或者高级流
  • 之前学习的字节流可以称为原始流
  • 字节缓冲流自带8KB缓冲区
  • 作用:缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性能
package com.itheima.d1_byte_buffer;

import java.io.*;

/**
    目标:使用字节缓冲流完成数据的读写操作。
 */
public class ByteBufferDemo {
    public static void main(String[] args) {

        try (
                // 这里面只能放置资源对象,用完会自动关闭:
                // 自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
                // 1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("D:\\resources\\newmeinv.jpeg");
                // a.把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);
                // 2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("D:\\resources\\newmeinv222.jpeg");
                // b.把字节输出流管道包装成高级的缓冲字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);

        ) {

            // 3、定义一个字节数组转移数据
            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();
        }

    }
}

建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式

6.2 字符缓冲流

  • 作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能
  • 字符缓冲输入流读取一行功能
    在这里插入图片描述
  • 字符缓冲输出流换行功能
    在这里插入图片描述

6.2.1 缓冲字符输入流

package com.itheima.d3_char_buffer;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class BufferedReaderDemo1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个文件字符输入流与源文件接通。
                Reader fr = new FileReader("src/log.txt");
                // a、把低级的字符输入流包装成高级的缓冲字符输入流。
                BufferedReader br = new BufferedReader(fr);
                ){

            // 2.1 用循环,每次读取一个字符数组的数据。  1024 + 1024 + 8
            char[] buffer = new char[1024]; // 1K字符
            int len;
            while ((len = br.read(buffer)) != -1) {
                String rs = new String(buffer, 0, len);
                System.out.println("rs = " + rs);
            }

            // 2.2 readLine
            String line;
            while ((line = br.readLine()) != null){
                System.out.println("line = " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6.2.2 缓冲字符输入流

package com.itheima.d3_char_buffer;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.Writer;

public class BufferedWriterDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        // Writer fw = new FileWriter("src/out02.txt"); 
        // 覆盖管道,每次启动都会清空文件之前的数据
        Writer fw = new FileWriter("src/out02.txt", true); // 追加数据
        BufferedWriter bw = new BufferedWriter(fw);

        // 2.1 写一个字符出去
        bw.write(98);
        bw.write('a');
        bw.write('徐'); // 不会出问题了
        bw.newLine(); // bw.write("\r\n"); // 换行

        // 2.2 写一个字符串出去
        bw.write("abc我是中国人");
        bw.newLine(); // bw.write("\r\n"); // 换行


        // 2.3 写一个字符数组出去
        char[] chars = "abc我是中国人".toCharArray();
        bw.write(chars);
        bw.newLine(); // bw.write("\r\n"); // 换行


        //2.4 写字符串的一部分出去
        bw.write("abc我是中国人", 0, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行

        //2.5 写字符数组的一部分出去
        bw.write(chars, 3, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行


        // fw.flush();// 刷新后流可以继续使用
        bw.close(); // 关闭包含刷线,关闭后流不能使用

    }
}

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

7 转换流

7.1 问题引出:不同编码读取乱码问题

  • 代码编码和文件编码不一致,使用字符流直接读取会乱码

7.2 字符输入转换流

package com.itheima.d4_transfer_stream;
import java.io.*;

public class InputStreamReaderDemo01 {
    public static void main(String[] args) throws Exception {
        // 代码UTF-8   文件 GBK  "D:\\resources\\data.txt"
        // 1、提取GBK文件的原始字节流。   abc 我
        //                            ooo oo
        InputStream is = new FileInputStream("D:\\resources\\data.txt");
        // 2.1 把原始字节流转换成字符输入转换流
        // 以指定的GBK编码转换成字符输入流  完美的解决了乱码问题
        Reader isr = new InputStreamReader(is , "GBK"); 
        // 2.2 把字符输入转换流换成缓冲流
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

7.3 字符输出转换流

package com.itheima.d4_transfer_stream;

import java.io.*;
import java.nio.Buffer;
public class OutputStreamWriterDemo02 {
    public static void main(String[] args) throws Exception {
        // 1、定义一个字节输出流
        OutputStream os = new FileOutputStream("io-app2/src/out03.txt");

        // 2、把原始的字节输出流转换成字符输出流
        Writer osw = new OutputStreamWriter(os , "GBK"); // 指定GBK的方式写字符出去

        // 3、把低级的字符输出流包装成高级的缓冲字符输出流。
        BufferedWriter bw = new BufferedWriter(osw);

        bw.write("我爱中国1~~");
        bw.write("我爱中国2~~");
        bw.write("我爱中国3~~");

        bw.close();
    }
}

8 序列化对象

8.1 对象序列化

  • 以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化
  • 对象必须实现序列化接口
package com.itheima.d5_serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

/**
  对象如果要序列化,必须实现Serializable序列化接口。
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
    // 申明序列化的版本号码
    // 序列化的版本号与反序列化的版本号必须一致才不会出错!
    private static final long serialVersionUID = 1;
    private String name;
    private String loginName;
    // transient修饰的成员变量不参与序列化了
    // 密码信息应该保密 不适合参与序列化
    private transient String passWord;
    private int age ;
}

  • 对象序列化
package com.itheima.d5_serializable;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建学生对象
        Student s = new Student("陈磊", "chenlei","1314520", 21);

        // 2、对象序列化:使用对象字节输出流包装字节输出流管道
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/student.txt"));

        // 3、直接调用序列化方法
        oos.writeObject(s);

        // 4、释放资源
        oos.close();
        System.out.println("序列化完成了~~");

    }
}

8.2 对象反序列化

package com.itheima.d5_serializable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;

/**
    目标:学会进行对象反序列化:使用对象字节输入流把文件中的对象数据恢复成内存中的Java对象。
 */
public class ObjectInputStreamDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建对象字节输入流管道包装低级的字节输入流管道
        ObjectInputStream is = new ObjectInputStream(new FileInputStream("src/obj.txt"));

        // 2、调用对象字节输入流的反序列化方法
        Student s = (Student) is.readObject();
        System.out.println(s);
    }
}

注意:当学生类代码更改之后,序列化的版本号也可以进行更新,此时,必须要再次运行;序列化代码,更新版本号,之后运行反序列化代码才不会出错

9 打印流

9.1 PrintStream、PrintWriter

  • 作用:打印流可以实现方便、高效的打印数据到文件中去
  • 可以实现打印什么数据就是什么数据
package com.itheima.d6_printStream;

import java.io.*;
public class PrintDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个打印流对象
        // 1.1 创建一个低级流
        OutputStream os = new FileOutputStream("src/print.txt" , true);
        // 能否追加数据 是在低级流这里设置的
        OutputStream os1 = new FileOutputStream("src/print.txt" );
        // 1.2 创建打印流
        PrintStream ps1 = new PrintStream(os);
        PrintStream ps2 = new PrintStream(os1);
        // 1.3 打印功能上与PrintStream的使用没有区别
        PrintWriter ps = new PrintWriter(os); 

        ps.println(97);
        ps.println('a');
        ps.println(23.3);
        ps.println(true);
        ps.println("我是打印流输出的,我是啥就打印啥");

        ps.close();
    }
}

9.2 输出语句的重定向

  • 属于打印流的一种应用,可以把输出语句的打印位置改到文件
package com.itheima.d6_printStream;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("锦瑟无端五十弦");
        System.out.println("一弦一柱思华年");

        // 改变输出语句的位置(重定向)
        PrintStream ps = new PrintStream("io-app2/src/log.txt");
        System.setOut(ps); // 把系统打印流改成我们自己的打印流

        System.out.println("庄生晓梦迷蝴蝶");
        System.out.println("望帝春心托杜鹃");
    }
}

补充知识:Properties

  • Properties代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去
  • 属性文件:后缀是.properties结尾的文件,里面的内容都是 key=value,后续做系统配置信息的

补充知识:IO框架

  • commons-io是apache开源基金组织提供的一组有关IO操作的类库,提高IO功能开发的效率
  • commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils, IOUtils
  • FileUtils主要有如下方法:
    在这里插入图片描述
  • 导入commons-io-2.6.jar做开发
package com.itheima.d8_commons_io;
import javafx.scene.shape.Path;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.file.Files;

public class CommonsIODemo01 {
    public static void main(String[] args) throws Exception {

        // 1.完成文件复制!
        IOUtils.copy(new FileInputStream("src/data01.txt"),
                new FileOutputStream("src/com/itheima/d1_byte_buffer/data01.txt"));

        // 2.完成文件复制到某个文件夹下!
        FileUtils.copyFileToDirectory(new File("src/data01.txt"),
                new File("src/com/itheima/d2_byte_buffer_time"));

        // 3.完成文件夹复制到某个文件夹下!
        FileUtils.copyDirectoryToDirectory(new File("src/com/itheima/d1_byte_buffer") ,
                new File("src/com/itheima/d2_byte_buffer_time"));

        // 4. 删除文件夹
        FileUtils.deleteDirectory(new File("D:\\new"));
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值