java--IO

1.文件流

2.常用的文件操作

(1)根据路径构建一个File对象

public class CreateFile {

    public static void main(String[] args) {
        String filePath="D:\\io\\hello.txt";
        create1(filePath);
    }

    //根据路径构建一个File对象
    public static void create1(String filePath){
        //在内存中有了一个file对象
        File file = new File(filePath);
        try {
            file.createNewFile();//写入到磁盘对应的位置
            System.out.println("文件创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
}

(2)根据父目录文件+子路径构建

    //根据父目录文件+子路径构建
    public static void create2(String parent,String fileName){
        File parentFile = new File(parent);
        File file = new File(parentFile, fileName);
        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

(3)根据父目录+子路径构建

    //根据父目录+子路径构建
    public static void create3(String parent,String fileName){
        File file = new File(parent, fileName);
        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

(4)获取文件相关信息

public class GetInformationInFile {

    public static void main(String[] args) {
        String path="d:\\io\\hello.txt";
        info(path);
    }

    public static void info(String filePath){
        //先创建文件对象
        File file = new File(filePath);
        //得到文件名
        System.out.println("文件名="+file.getName());
        //得到文件绝对路径
        System.out.println("文件绝对路径="+file.getAbsolutePath());
        //得到文件父级目录
        System.out.println("文件=父级目录"+file.getParent());
        //得到文件大小(字节)
        System.out.println("文件大小="+file.length());
        //查看文件是否存在
        System.out.println("是否存在="+file.exists());
        //是不是一个文件
        System.out.println("是否是一个文件="+file.isFile());
        //是不是一个目录
        System.out.println("是否是一个目录="+file.isDirectory());
    }
}

(5)目录的操作和文件的删除

public class Directories {

    public static void main(String[] args) {
        //String path="D:\\io\\hello.txt";
        //m1(path);
        String path="D:\\io\\111";
        m3(path);
    }

    //判断文件是否存在 如果存在就删除
    public static void m1(String path){
        File file = new File(path);
        if (file.exists()){
            if (file.delete()){
                System.out.println(path+"删除成功");
            }else {
                System.out.println(path+"删除失败");
            }
        }else {
            System.out.println("该文件不存在");
        }
    }

    //判断目录是否存在 如果存在就删除
    //在java编程中 目录也当作文件
    public static void m2(String path){
        File file = new File(path);
        if (file.exists()){
            if (file.delete()){
                System.out.println(path+"删除成功");
            }else {
                System.out.println(path+"删除失败");
            }
        }else {
            System.out.println("该目录不存在");
        }
    }

    //判断目录是否存在 如果存在就提示存在,如果不存在就删除
    public static void m3(String path){
        File file = new File(path);
        if (file.exists()){
            System.out.println("该目录存在");
        }else {
            //创建多级目录
            if (file.mkdirs()){
                System.out.println(path+" 目录创建成功");
            }else {
                System.out.println(path+" 目录创失败");
            }
        }
    }
}

3.IO流原理及流的分类

(1)流的分类

(1)按操作数据单位不同分为:字节流(保证操作二进制文件无损操作)   字符流(按字符读取,效率高,操作文本文件)

(2)按数据流的方向不同:   输入流       输出流

(3)按流的角色不同:      节点流        处理流

(2)字节输入流(InputStream)

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\hello.txt";
        readFile2(path);
    }

    /**
     * 演示读取文件
     * 单个字节读取 读取效率低
     * @param path
     */
    public static void readFile1(String path){
        int readData=0;
        FileInputStream fileInputStream=null;
        try {
            //创建FileInputStream对象 用于读取文件
            fileInputStream = new FileInputStream(path);
            //从该输入流读取一个字节的数据 如果没有输入可用 此方法将阻止
            //如果返回-1 表示读取完毕
            while ((readData=fileInputStream.read())!=-1){
                System.out.print((char) readData+" ");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭文件流  释放资源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 使用read(byte[] b)读取文件 提高效率
     * @param path
     */
    public static void readFile2(String path){
        int readLen=0;
        //字节数组
        byte[] buf=new byte[8];//一次读取8个字节
        FileInputStream fileInputStream=null;
        try {
            //创建FileInputStream对象 用于读取文件
            fileInputStream = new FileInputStream(path);
            //从该输入流读取buf.length字节的数据 此方法将阻塞,直到某些输入可用
            //如果返回-1 表示读取完毕
            //如果读取正常 返回实际读取的字节数
            while ((readLen=fileInputStream.read(buf))!=-1){
                System.out.println(new String(buf,0,readLen));//转换为字符串显示
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭文件流  释放资源
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

(3)字节输出流(FileOutputStream)

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\test.txt";
        writeFile(path);
    }

    /**
     * 演示使用FileOutputStream
     * 将数据写入文件中,如果该文件不存在,则创建该文件
     * 当写入内容时,会覆盖原来的内容
     * 如果不想覆盖:new FileOutputStream(path,true),则以追加的形式写入
     * @param path
     */
    public static void writeFile(String path){
        //创建FileOutputStream对象
        FileOutputStream fileOutputStream=null;
        try {
            //得到FileOutputStream对象
            fileOutputStream=new FileOutputStream(path);

            //写入一个字节
            //fileOutputStream.write('t');

            //写入字符串
            //str.getBytes()->可以把字符串转为字节数组
            String str="TangMeng";
            fileOutputStream.write(str.getBytes());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

(4)文件拷贝


(5)字符输入流(FileReader)

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        fileReaderTest2(path);
    }

    /**
     *使用字符输入流操作文件
     * 每次读取单个字符
     */
    public static void fileReaderTest(String path){

        FileReader fileReader=null;
        int data=0;

        try {
            fileReader=new FileReader(path);
            //循环读取 每次读取单个字符
            while ((data=fileReader.read())!=-1){
                System.out.println((char) data);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }


    /**
     *使用字符输入流操作文件
     *使用字符数组来读取文件
     */
    public static void fileReaderTest2(String path){

        FileReader fileReader=null;
        char[] buf=new char[8];
        int readLen=0;

        try {
            fileReader=new FileReader(path);
            //循环读取 返回的是实际读取的字符数
            //如果返回-1,说明到文件结束
            while ((readLen=fileReader.read(buf))!=-1){
                System.out.print(new String(buf,0,readLen));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

(6)字符输出流(FileWriter)

FileWriter使用后必须要关闭或者刷新,才能将内容写入文件
public class test {

    public static void main(String[] args) {
        String path="d:\\io\\haha.txt";
        fileWriterTest(path);
    }

    /**
     *使用字符输出流操作文件
     */
    public static void fileWriterTest(String path){

        FileWriter fileWriter=null;
        char[] chars={'a','b','c'};

        try {
            fileWriter=new FileWriter(path,true);
            //写入单个字符
            fileWriter.write('H');
            //写入指定数组
            fileWriter.write(chars);
            //写入指定数组的指定部分
            fileWriter.write("哈哈哈".toCharArray(),0,2);
            //写入整个字符串
            fileWriter.write("哈哈");
            //写入字符串的指定部分
            fileWriter.write("哈哈哈哈哈哈",4,3);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //fileWriter需要关闭流或者flush才能把数据真正写入到文件
            try {
                fileWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

}

4.节点流和处理流

在这里插入图片描述

(1)节点流

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

(2)处理流(包装流)

处理流封装已经存在的流,为程序提供更为强大的读写功能

性能提高:主要以增加缓冲的方式来提高输入输出效率
操作便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

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

(1)节点流是底层流/低级流,直接跟数据源相接
(2)处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
(3)处理流对节点流进行包装,使用了修饰器模式,不会直接与数据源相连

(4)BufferedReader

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\haha.txt";
        bufferReaderTest(path);
    }

    /**
     *使用处理流操作文件
     */
    public static void bufferReaderTest(String path){
        BufferedReader bufferedReader=null;
        try {
            bufferedReader=new BufferedReader(new FileReader(path));
            //读取
            String line;
            //bufferedReader.readLine() 按行读取  当返回null时,表示文件读取完毕
            while ((line=bufferedReader.readLine())!=null){
                System.out.println(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //关闭流 只需要关闭bufferedReader就可以了,因为底层会自动关闭节点流
            try {
                bufferedReader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

}

(5)BufferedWriter

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\haha.txt";
        bufferWriterTest(path);
    }

    /**
     *使用处理流操作文件
     */
    public static void bufferWriterTest(String path) {
        BufferedWriter bufferedWriter=null;
        try {
            bufferedWriter=new BufferedWriter(new FileWriter(path,true));
            bufferedWriter.write("哈哈哈");
            bufferedWriter.newLine();//插入一个和系统相关的换行符
            bufferedWriter.write("哈哈哈");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //关闭流
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

(6)完成文本文件拷贝

public class test {

    public static void main(String[] args) {
        String from="d:\\io\\haha.txt";
        String to="d:\\io\\haha1.txt";
        bufferCopyTest(from,to);
    }

    /**
     *使用处理流拷贝文件
     */
    public static void bufferCopyTest(String from,String to) {

        BufferedReader bufferedReader=null;
        BufferedWriter bufferedWriter=null;
        String line=null;

        try {
            bufferedReader=new BufferedReader(new FileReader(from));
            bufferedWriter=new BufferedWriter(new FileWriter(to));
            //读取
            //readLine()读取一行的数据 但没有都换行符
            while ((line=bufferedReader.readLine())!=null){
                //每读取一行 就写出
                bufferedWriter.write(line);
                //插入换行
                bufferedWriter.newLine();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //关闭流
            try {
                bufferedReader.close();
                bufferedWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

(7)BufferedInputStream和BufferedOutputStream实现图片拷贝

public class test {

    public static void main(String[] args) {
        String from="d:\\io\\2.jpg";
        String to="d:\\io\\3.jpg";
        bufferCopyTest(from,to);
    }

    /**
     *使用处理流拷贝文件
     */
    public static void bufferCopyTest(String from,String to) {
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        try {
            bis=new BufferedInputStream(new FileInputStream(from));
            bos=new BufferedOutputStream(new FileOutputStream(to));
            //循环读取文件,并写出到目的地
            byte[] buf=new byte[1024];
            int readLen=0;
            //当返回-1时,就表示文件读取完毕
            while ((readLen= bis.read(buf))!=-1){
                bos.write(buf,0,readLen);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                bis.close();
                bos.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

5.对象处理流


(1)ObjectInputStream:提供反序列化功能 

(2)ObjectOutputStream:提供序列化功能 

(1)ObjectOutputStream

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\xu";
        objectOutputStreamTest(path);
    }

    /**
     *使用objectOutputStream,完成数据的序列化
     * 序列化后保存的文件格式不是纯文本的,而是按照要保存的格式保存的
     */
    public static void objectOutputStreamTest(String path) {
        ObjectOutputStream oos=null;
        try {
            oos=new ObjectOutputStream(new FileOutputStream(path,true));
            //序列化数据到文件中
            oos.writeInt(100);//int -> Integer(实现了Serializable)
            oos.writeBoolean(true);//boolean -> Boolean
            oos.writeChar('a');//char -> Character
            oos.writeDouble(1.8);//double -> Double
            oos.writeUTF("小白");//String
            //保存一个dog对象
            oos.writeObject(new Dog("旺财",1));
            System.out.println("保存数据完毕");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                oos.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Dog implements Serializable{

    private String name;
    private int age;


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

	    public String getName(){
        return name;
    }

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

(2)ObjectInputStream

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\xu";
        objectInputStreamTest(path);
    }

    /**
     *使用objectInputStream,完成数据的反序列化
     */
    public static void objectInputStreamTest(String path) {
        ObjectInputStream ois=null;
        try {
            ois=new ObjectInputStream(new FileInputStream(path));
            //读取
            //读取的顺序需要和保存时的顺序一致
            System.out.println(ois.readInt());
            System.out.println(ois.readBoolean());
            System.out.println(ois.readChar());
            System.out.println(ois.readDouble());
            System.out.println(ois.readUTF());
            Dog dog =(Dog) ois.readObject();
            System.out.println(dog);//底层:Object->dog
            dog.getName();//可以调用dog类里边的方法
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                ois.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Dog implements Serializable{

    private String name;
    private int age;


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

    public String getName(){
        return name;
    }

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

(3)对象处理流使用细节

(1)读写顺序一致

(2)要求序列化或反序列化的对象,需要实现 Serializable

(3)序列化类中建议添加SerialVersionUID,可以提高版本的兼容性。加了版本号的话,以后对该类的修改
	会看做一次修改而不是当作一个新类

(4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

(5)序列化对象时,要求里面属性的类型也需要实现序列化接口

(6)序列化具备可继承性,如果没类实现了可序列化,则它的所有子类也已经默认实现了

6.标准输入输出流

System.in    标准输入   键盘  
System.out   标准输出   显示器

7.转换流

将字节流转换为字符流
为了防止读取时出现的中文乱码问题

(1)InputStreamReader

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        inputStreamReaderTest(path);
    }

    /**
     *使用 InputStreamReader 转换流解决中文乱码问题
     * 将字节流FileInputStream 转换成字符流InputStreamReader,指定编码utf-8
     */
    public static void inputStreamReaderTest(String path) {
        InputStreamReader inputStreamReader=null;
        BufferedReader bufferedReader=null;
        try {
            //将FileInputStream转为InputStreamReader,指定编码utf-8
            inputStreamReader=new InputStreamReader(new FileInputStream(path),"utf-8");
            //把InputStreamReader传入 BufferedReader
            bufferedReader=new BufferedReader(inputStreamReader);
            //读取
            String s = bufferedReader.readLine();
            System.out.println("读取到内容="+s);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            //关闭流
            try {
                bufferedReader.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

(2)OutputStreamWriter

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        outputStreamWriterTest(path);
    }

    /**
     *使用 OutputStreamWriter
     * 将字节流FileOutputStream 转换成字符流OutputStreamWriter,指定编码utf-8
     */
    public static void outputStreamWriterTest(String path) {
        OutputStreamWriter osw=null;
        try {
            osw=new OutputStreamWriter(new FileOutputStream(path,true),"utf-8");
            osw.write("哈哈哈,傻子");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                osw.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

8.打印流

(1)PrintStream(字节流)

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        printStreamTest(path);
    }

    /**
     *使用 PrintStream(字节打印流)
     */
    public static void printStreamTest(String path) {
        PrintStream out=System.out;
        //在默认情况下,PrintStream输出数据的位置是显示器
        out.print("hello!world");
        //因为print的底层使用的是write,所以可以直接调用write进行打印
        try {
            out.write("哈哈".getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        out.close();
        //可以修改打印流输出的位置
        try {
            System.setOut(new PrintStream(path));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        System.out.println(333);
    }
}

(2)PrintWriter(字符流)

public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        printWriterTest(path);
    }

    /**
     *使用 PrintWriter(字符打印流)
     */
    public static void printWriterTest(String path) {
        
        PrintWriter printWriter=null;
        
        //输出到控制台
        printWriter=new PrintWriter(System.out);
        printWriter.print("12345678");

        //修改输出位置
        try {
            printWriter=new PrintWriter(new FileWriter(path));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        printWriter.print("你好呀");
        printWriter.close();
    }
}

9.Properties类

(1)load:加载配置文件的键值对到Properties对象

(2)list:将数据显示到指定设备

(3)getProperty(key):根据键获取值

(4)setProperty(key,value):设置键值对到Properties对象

(5)store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,
	会存储为unicode码
public class test {

    public static void main(String[] args) {
        String path="d:\\io\\ha.txt";
        testProperties();
    }

    public static void testProperties(){
        //1.创建Properties对象
        Properties properties = new Properties();
        //2.加载指定配置文件
        try {
            properties.load(new FileReader("src\\mysql.properties"));
            //3.把键值对显示在控制台
            properties.list(System.out);
            //4.根据key获取对应的value
            String name= properties.getProperty("name");
            System.out.println(name);
            //5.向配置文件添加内容
            properties.setProperty("charset","utf8");
            properties.setProperty("ha","hah");
            properties.store(new FileOutputStream("src\\mysql.properties"),null);
            System.out.println("保存成功");
			//6.修改键值对 setProperty(key,value)方法:
            //如果该文件没有对应的key,就是创建;如果有对应的key,就是修改
            properties.setProperty("ha","hahahaha");
            properties.store(new FileOutputStream("src\\mysql.properties"),null);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Java T-io中,可以通过Config类来配置T-io的各种参数,包括连接超时时间、心跳检测等。Config类位于org.tio.common包下,具体的配置项如下: 1. setReadBufferSize:设置读缓冲区大小。 2. setWriteBufferSize:设置写缓冲区大小。 3. setHeartbeatTimeout:设置心跳超时时间,单位为毫秒。 4. setIfServer:设置是否为服务器模式。 5. setBindIp:设置绑定的IP地址。 6. setBindPort:设置绑定的端口号。 7. setClientNode:设置是否为客户端节点。 8. setServerGroupContext:设置ServerGroupContext对象,包含了服务器的各种配置信息。 9. setReadTimeout:设置读超时时间,单位为毫秒。 10. setWriteTimeout:设置写超时时间,单位为毫秒。 11. setUseQueueDecode:设置是否使用队列解码。 12. setUseQueueSend:设置是否使用队列发送。 13. setUseQueueSendAndClose:设置是否使用队列发送并关闭。 14. setUseSession:设置是否使用Session。 15. setUseSsl:设置是否使用SSL。 16. setValidAfterSecond:设置连接有效时间,单位为秒。 17. setValidIfSilent:设置如果连接保持沉默是否有效。 18. setIpStatDuration:设置IP统计的时间间隔,单位为秒。 19. setIpStatListener:设置IP统计监听器。 20. setStatPath:设置统计文件保存路径。 21. setStatInterval:设置统计间隔时间,单位为秒。 22. setMaxLiveTimeOfStaticRes:设置静态资源的最大存活时间,单位为毫秒。 23. setGroupExecutorKeepAliveTime:设置线程池的最大存活时间,单位为秒。 24. setGroupExecutorThreadFactory:设置线程池的线程工厂。 25. setGroupExecutorCorePoolSize:设置线程池的核心线程数。 26. setGroupExecutorMaxPoolSize:设置线程池的最大线程数。 27. setGroupExecutorQueueCapacity:设置线程池的队列容量。 28. setGroupExecutorRejectedPolicy:设置线程池的拒绝策略。 29. setAioExecutorThreadFactory:设置AIO线程池的线程工厂。 30. setAioExecutorCorePoolSize:设置AIO线程池的核心线程数。 31. setAioExecutorMaxPoolSize:设置AIO线程池的最大线程数。 32. setAioExecutorQueueCapacity:设置AIO线程池的队列容量。 33. setAioExecutorRejectedPolicy:设置AIO线程池的拒绝策略。 通过设置Config对象的各种参数,可以对T-io进行灵活的配置和调整,以适应不同的应用场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cw旧巷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值