Java--流

数据源:

数据源data source,提供数据的原始媒介。常见的数据源有:数据库、文件、其他程 序、内存、网络连接、lo 设备。 数据源分为:源设备、目标设备。

源设备:为程序提供数据,一般对应输入流。

目标设备:程序数据的目的地,一般对应输出流。

流的概念:

流是一个抽象、动态的概念,是一连串连续动态的数据集合。 对于输入流而言,数据源就像水箱,流(stream)就像水管中流动着的水流,程序就是我们最终的用户。我们通过流(AStream)将数据源(Source)中的数据(information)输送到程序(Program)中。对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。

Java中流的概念细分

按流的方向分类:

输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。 输出流:数据流向是程序到目的地(以 OutPutStream、Writer结尾的流)。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
//文件不规范写法
​
public class Test {
    public static void main(String[] args) throws IOException {
        readfile();
        writeFile();
    }
    public static void readfile() throws IOException {
        try (FileInputStream fis = new FileInputStream("D:/b.txt");){
​
            int x = fis.read();
            char y = (char) fis.read();
            char z = (char) fis.read();
            char w = (char) fis.read();
            int r  = fis.read();//读取完毕返回-1
            System.out.println((char)x);
            System.out.println(y);
            System.out.println(z);
            System.out.println(w);
            System.out.println(r);
//            fis.close();//不关闭,操作系统打开的系统资源文件一直被打开
            //通过操作系统打开文件,硬盘资源,不做关闭时,资源一直被打开//打出信号让操作系统去关闭文件
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void writeFile() throws IOException {
        FileOutputStream fis = null;
        try {
           fis = new FileOutputStream("d:/b.txt");
            fis.write("wsxz".getBytes(StandardCharsets.UTF_8));//转为字节数组输入
            fis.write('s');
            fis.write("t521".getBytes(StandardCharsets.UTF_8));
            fis.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        finally{
            if (fis != null) {
                fis.close();
            }
        }
    }
}
​
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
​
public class Test2 {
    public static void main(String[] args) throws IOException {
        readFile();
    }
    public static void readFile() throws IOException {
        FileInputStream x = null;
        try {
            x = new FileInputStream("d:/b.txt");
            int y = x.read();
            int z = x.read();
            int w = x.read();
            int a = x.read();
            int b = x.read();
            System.out.println(y);
            System.out.println(z);
            System.out.println(w);
            System.out.println(a);
            System.out.println(b);
​
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {//文件最后不管前面是否报错都会将文件关闭
            if(x != null)
                x.close();
        }
    }
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
​
public class Test3 {
    public static void main(String[] args) throws IOException {
        readFile();
    }
    public static void readFile() throws IOException {
        try (FileInputStream x = new FileInputStream("d:/b.txt");){//编译器自动生成finally结构关闭文件
            int y = x.read();
            int z = x.read();
            int w = x.read();
            int a = x.read();
            int b = x.read();
            System.out.println(y);
            System.out.println(z);
            System.out.println(w);
            System.out.println(a);
            System.out.println(b);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

按处理的数据单元分类:

字节流:以字节为单位获取数据,命名上以Stream结屋的流一般是字节流 。如FilelnputStream、FileOutputStream。

字符流:以字符为单位获取数据,命名上以Reader/Writer结屋的流一般是字符流,如 FileReaderFileWriter

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
​
public class Test4 {
    public static void main(String[] args) {
        readFile();
        writeFile();
        CopyFile();
    }
    public static  void readFile()
    {
        try (FileInputStream x = new FileInputStream("d:/b.txt");){
            StringBuilder y = new StringBuilder();
            int temp = 0;
            while((temp = x.read()) != -1)
            {
                y.append((char) temp);
            }
            System.out.println(y);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void writeFile()
    {
        FileOutputStream z = null;
        try {
            z = new FileOutputStream("d:/b.txt");
            z.write("wsxzst5626454664".getBytes(StandardCharsets.UTF_8));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                z.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
  public static void CopyFile(){
        try(FileInputStream c = new FileInputStream("d:/微信图片.jpG");
        FileOutputStream v = new FileOutputStream("d:/微信图片复制.jpG");){
            int temp = 0;
            while((temp = c.read()) != -1)
            {
                v.write(temp);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void CopyFile(){
        try(FileInputStream c = new FileInputStream("d:/微信图片.jpG");
            FileOutputStream v = new FileOutputStream("d:/微信图片复制2.jpG");){
            byte[] buff = new byte[1024];
            while((c.read(buff)) != -1)
            {
                v.write(buff);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
​
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
​
public class Test5 {
    public static void main(String[] args) {
        try(FileReader x = new FileReader("d:/c.txt");
            FileWriter y = new FileWriter("d:/c_copy.txt");){
            int temp = 0;
            while((temp = x.read()) != -1) {
                y.write(temp);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
​

按处理对象不同分类:

节点流:可以直接从数据源或目的地读写数据,如 FilelnputStream、FileReaderDatalnputStream等。

处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如 BufferedInputStream、BufferedReader等。

import java.io.*;
​
public class Test6 {
    public static void main(String[] args) {
    try(FileInputStream x = new FileInputStream("d:/微信图片.jpG");
        FileOutputStream y = new FileOutputStream("d:/微信图片2.jpG");
        BufferedInputStream z = new BufferedInputStream(x);
        BufferedOutputStream w = new BufferedOutputStream(y);){
        int temp = 0;
        while((temp = x.read()) != -1)
        {
            w.write(temp);
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    }
}
​

文件字符流

前面介绍的文件字节流可以处理所有的文件,但是字节流不能很好的处理Unicode字符,经常会出现“乱码”现象。所以,我们处理文本文件,一般可以使用文件字符流,它以字符为单位进行操作。

import java.io.*;
​
public class Test9 {
    public static void main(String[] args) {
        writeDate();
        readData();
    }
    public static void writeDate(){
        try(DataOutputStream x = new DataOutputStream(new FileOutputStream("d:/data.txt"))) {
            x.writeChars("wsx");
            x.writeInt(85);
            x.writeChar('x');
            x.writeInt(12);
            x.writeBoolean(true);
            x.writeUTF("吴时兴");
            x.flush();//刷新缓存区,将流中数据写入文件
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void readData()
    {
        try(DataInputStream y = new DataInputStream(new FileInputStream("d:/data.txt"))){
            System.out.println(y.readChar());
            System.out.println(y.readChar());
            System.out.println(y.readChar());
            System.out.println(y.readInt());
            System.out.println(y.readChar());
            System.out.println(y.readInt());
            System.out.println(y.readBoolean());
            System.out.println(y.readUTF());
​
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

缓冲字节流

Java缓冲流本身并不具有10流的读取与写入功能,只是在别的 流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。 当对文件或者其他数据源进行频繁的读写操作时,效率比较低, 这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。 因此,缓冲流还是很重要的,我们在10操作时记得加上缓冲流来提升性能。BufferedInputStream和BufferedOutputStream这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。下面我们通过两种方式(普通文件字节流与缓冲文件字节流)实现一个视频文件的复制,来体会一下缓冲流的好处。

import java.io.*;
​
public class Test7 {
    public static void main(String[] args) {
        try(BufferedReader x = new BufferedReader(new FileReader("d:/c.txt"));
            BufferedWriter y = new BufferedWriter(new FileWriter("d:/c4.txt"));){
            String temp = "";
            while((temp = x.readLine()) != null)
            {
                y.write(temp);
                y.newLine();
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
import java.io.*;
​
public class Test6 {
    public static void main(String[] args) {
    try(FileInputStream x = new FileInputStream("d:/微信图片.jpG");
        FileOutputStream y = new FileOutputStream("d:/微信图片2.jpG");
        BufferedInputStream z = new BufferedInputStream(x);
        BufferedOutputStream w = new BufferedOutputStream(y);){
        int temp = 0;
        while((temp = x.read()) != -1)
        {
            w.write(temp);
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    }
}

缓冲字符流

BufferedReader/BufferedWriter增加了缓存机制,大大提高了读写文本文件的效率,同时,提供了更方便的按行读取的方法:readLine();处理文本时,我们一般可以使用缓冲字符流。

import java.io.*;
​
public class Test7 {
    public static void main(String[] args) {
        try(BufferedReader x = new BufferedReader(new FileReader("d:/c.txt"));
            BufferedWriter y = new BufferedWriter(new FileWriter("d:/c4.txt"));){
            String temp = "";
            while((temp = x.readLine()) != null)
            {
                y.write(temp);
                y.newLine();
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
​

字节数组流

ByteArrayInputStream和ByteArrayOutputStream经常用在需要流和数组之间转化的情况!说白了,FilelnputStream是把文件当做数据源。ByteArrayInputStream则是把内存中的”某个字节数组对象”当做数据源。

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
​
public class Test8 {
    public static void main(String[] args) {
        test("dsafsgagd".getBytes(StandardCharsets.UTF_8));
    }
    public static void test(byte[] bytes){
        int temp = 0;
        int num = 0;
        try(ByteArrayInputStream x = new ByteArrayInputStream(bytes)){
            while((temp = x.read()) != -1){
                System.out.println((char) temp);
                num++;
            }
            System.out.println("读取字节数组为" + num);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
​

数据流

数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型。 DatalnputStream和DataOutputStream提供了可以存取与机器无关的所有Java基础类型数据(如:int、double、String等)的方法。 DatalnputStream和DataOutputStream是处理流,可以对其他节点流或处理流进行包装,增加一些更灵活、更高效的功能。

import java.io.*;
​
public class Test9 {
    public static void main(String[] args) {
        writeDate();
        readData();
    }
    public static void writeDate(){
        try(DataOutputStream x = new DataOutputStream(new FileOutputStream("d:/data.txt"))) {
            x.writeChars("wsx");
            x.writeInt(85);
            x.writeChar('x');
            x.writeInt(12);
            x.writeBoolean(true);
            x.writeUTF("撒旦今年");
            x.flush();//刷新缓存区,将流中数据写入文件
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void readData()
    {
        try(DataInputStream y = new DataInputStream(new FileInputStream("d:/data.txt"))){
            System.out.println(y.readChar());
            System.out.println(y.readChar());
            System.out.println(y.readChar());
            System.out.println(y.readInt());
            System.out.println(y.readChar());
            System.out.println(y.readInt());
            System.out.println(y.readBoolean());
            System.out.println(y.readUTF());
​
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

对象流

ObjectInputStream/ObjectOutputStream是以“对象”为数据源,但是必须将传输的对象进行序列化与反序列化操作。 需要序列化的对象,需要实现接口:iava.io.Serializable对象序列化的作用有如下两种: 持久化:把对象的字节序列永久地保存到硬盘上 通常存放在一 个文件中,比如:休眠的实现。以后服务器session管理,hibernate将对象持久化实现。 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。

不参与序列化

static属性不参与序列化。 对象中的某些属性如果不想被序列化,不能使用static,而是使用transient修饰。

public class User implements java.io.Serializable{
    private int id;
    private String name;
    transient private String pwd;
​
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public String getPwd() {
        return pwd;
    }
​
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}
import java.io.*;
import java.util.ArrayList;
​
public class Test10 {
    public static void main(String[] args) {
        writeObject();
        ReadObject();//密码没有参与序列化
    }
    public static void  writeObject(){
        try(ObjectOutputStream x = new ObjectOutputStream(new FileOutputStream("d:/Obj.txt"))){
            ArrayList<User> list = new ArrayList<>();
            list.add(new User(1001,"吴时兴","123456"));
            list.add(new User(1002,"吴时兴2","123458526"));
            list.add(new User(1003,"吴时兴3","123996"));
            list.add(new User(1004,"吴时兴4","1235656"));
            x.writeObject(list);
            x.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void ReadObject(){
        try(ObjectInputStream y = new ObjectInputStream(new FileInputStream("d:/Obj.txt"))){
            ArrayList<User> list  = (ArrayList)y.readObject();
            for(User u : list){
                System.out.println(u.getId()+ "," + u.getName() + "," + u.getPwd());
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}
import java.io.*;
import java.util.ArrayList;
​
public class Test10 {
    public static void main(String[] args) {
        writeObject();
        ReadObject();//密码没有参与序列化
    }
    public static void  writeObject(){
        try(ObjectOutputStream x = new ObjectOutputStream(new FileOutputStream("d:/Obj.txt"))){
            ArrayList<User> list = new ArrayList<>();
            list.add(new User(1001,"吴时兴","123456"));
            list.add(new User(1002,"吴时兴2","123458526"));
            list.add(new User(1003,"吴时兴3","123996"));
            list.add(new User(1004,"吴时兴4","1235656"));
            x.writeObject(list);
            x.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void ReadObject(){
        try(ObjectInputStream y = new ObjectInputStream(new FileInputStream("d:/Obj.txt"))){
            ArrayList<User> list  = (ArrayList)y.readObject();
            for(User u : list){
                System.out.println(u.getId()+ "," + u.getName() + "," + u.getPwd());
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

转换流

InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流。

import java.io.*;
​
public class Test11 {
    public static void main(String[] args) {
        try(BufferedReader x = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter y = new BufferedWriter(new OutputStreamWriter(System.out));){
            String str = x.readLine();
            while(!"exit".equals(str)){
                y.write("键盘输入:" + str);
                y.newLine();
                y.flush();
                str = x.readLine();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
​

随意访问文件流

RandomAccessFile可以实现两个作用: 1.实现对一个文件做读和写的操作。 2.可以访问文件的任意位置。不像其他流只能按照先后顺序读取。

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
​
public class Test12 {
    public static void main(String[] args) {
        try(RandomAccessFile x = new RandomAccessFile("d:/data.txt","rw")){
            int [] data = {10,20,3,63,52,85,96,85,74,20};
            for (int i = 0; i < data.length; i++) {
                x.writeInt(data[i]);
            }
            x.seek(4);
            System.out.println(x.readInt());
            x.seek(8);
            x.writeInt(45);
            for (int i = 0; i < 10; i++) {
                x.seek(i * 4);
                System.out.print(x.readInt() + "\t");
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

装饰器模式构建IO流体系

装饰器模式简介 装饰器模式是GOF23种设计模式中较为常用的一种模式。它 可以实现对原有类的包装和装饰,使新的类具有更强的功能。

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
public class Test14 {
    public static void main(String[] args) {
//        writeFile();
//        Read();
        ReadUrl();
//        FileCopy();
//        directoryCopy();
    }
    public static void writeFile(){
        StringBuilder x = new StringBuilder();
        for(int i = 0;i < 1000;i++)
        {
            x.append(Math.random() + "\n");
​
        }
        try {
            FileUtils.write(new File("d:/4.txt"),x.toString(),"gbk");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void Read(){
        try {
            List<String> y = FileUtils.readLines(new File("d:/4.txt"),"gbk");
            for(String temp : y)
            {
                System.out.println(temp);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void ReadUrl(){
        try {
            URL v = new URL("https://vidhub.cc//");
            InputStream b = v.openStream();
            String xo = IOUtils.toString(b,"UTF-8");
            System.out.println(xo);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void FileCopy(){
        File x = new File("d:/data.txt");
        File y = new File("d:/aa.txt");
        try {
            FileUtils.copyFile(x,y);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void directoryCopy(){
        File x1 = new File("d:/1");
        File x2 = new File("d:/3");
        try {
            FileUtils.copyDirectory(x1, x2, new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if(pathname.isDirectory() || pathname.getName().endsWith("jpG"))
                    {
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
//及就是新类包含原类并对与有原类的功能进行了添加

外导jar包的使用:

//阿帕奇开源代码导入commons下的IO流包
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
public class Test14 {
    public static void main(String[] args) {
//        writeFile();
//        Read();
        ReadUrl();
//        FileCopy();
//        directoryCopy();
    }
    public static void writeFile(){
        StringBuilder x = new StringBuilder();
        for(int i = 0;i < 1000;i++)
        {
            x.append(Math.random() + "\n");
​
        }
        try {
            FileUtils.write(new File("d:/4.txt"),x.toString(),"gbk");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void Read(){
        try {
            List<String> y = FileUtils.readLines(new File("d:/4.txt"),"gbk");
            for(String temp : y)
            {
                System.out.println(temp);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void ReadUrl(){
        try {
            URL v = new URL("https://vidhub.cc//");
            InputStream b = v.openStream();
            String xo = IOUtils.toString(b,"UTF-8");
            System.out.println(xo);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void FileCopy(){
        File x = new File("d:/data.txt");
        File y = new File("d:/aa.txt");
        try {
            FileUtils.copyFile(x,y);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void directoryCopy(){
        File x1 = new File("d:/1");
        File x2 = new File("d:/3");
        try {
            FileUtils.copyDirectory(x1, x2, new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if(pathname.isDirectory() || pathname.getName().endsWith("jpG"))
                    {
                        return true;
                    }
                    else{
                        return false;
                    }
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值