java基础之I/O流

file类:主要是操作电脑里的文件和文件夹

静态成员变量:

static String pathSeparator //路径分隔符 windows是分号,linux是冒号

static String Separator //文件(目录)名分隔符 windows是反斜杠\ ,linux是正斜杠/

路径:

1、路径不区分大小写

2、路径中文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠。

构造方法:

public File(String pathname) :创建新的 File实例。比较常用

参数:

         String pathname:字符串路径名称

         路径可以是文件结尾,也可以是文件夹结尾

、     可以是相对路径也可以是绝对路径

         创建File对象,只是把字符串路径封装成为File对象,不考虑路径真假情况。


public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。

参数:路径分成了两部分,父路径,子路径,方便使用。

          最终的结果:还是找的父路径与子路径合起来的路径,但分成两块书写。

          
public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
参数:

       只是父路径变成了File类型,可以使用File类的方法,对路径进行操作。

常用方法:

public String getAbsolutePath() :获取构造方法中的绝对路径。无论是绝对还是相对路径
public String getPath() :获取构造方法中传递的路径。
public String getName() : 获取构造方法传递路径的结尾部分(文件/文件夹)。
public long length() :获取的是构造方法指向的文件的大小,以字节为单位,若指的是文件夹,返回的是0。

file判断功能:

public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :判断构造方法中给定的路径是否以文件夹结尾。
public boolean isFile() :同样,判断否为文件结尾//路径必须是存在的,否则会返回flase
File类创建和删除方法:

public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。

注意:

          1、只能创建文件,不能创建文件夹

          2、创建文件路径必须存在,否则会抛出异常。

public boolean mkdir() :创建单级文件夹(目录)。
public boolean mkdirs() :创建单级或多级文件夹。

注意:

          创建的文件夹的路径和名称在构造方法中给出(构造方法的参数)


public boolean delete() :删除由构造方法路径中给出的文件或目录。 

file类目录遍历:

public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。

遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹名称,把获取到的多个名称存储到一个String类型的数组中。
public File[] listFiles() :返回一个File数组,遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹的名称,把文件/文件夹封装为File对象,多个File对象存储到File数组中。

注意: 

        遍历的是构造方法中给出的目录

        如果给出的路径不存在,会抛出空指针异常

       给出的路径不是一个目录,也会抛出空指针异常
 

递归:方法内调用自己

使用场景:方法主体不变,每次调用方法的参数不同

注:构造方法,禁止递归。直接编译报错。因为构造方法是创建对象用的,若有递归,那么一创建就会有无数个构造方法,出错。

使用递归的必须明确的两个条件:

                         递归的结束(什么时候结束)

                         递归的目的(一般是重复某种一样的操作或表达式)

 

过滤器:ListFiles方法,File类中两个ListFiles重载的方法,方法参数传递的就是过滤器

file[] listFiles(FileFilter filter)

              参数:

                      FileFilter:java.io.FileFilter接口,用于抽象路径名(File对象)的过滤器

             通过抽象方法boolean accept(File pathname)来过滤文件

       参数File pathname:使用ListFiles方法遍历目录,得到每一个文件对象。

File[]listFiles(FilenameFilter filter)

 参数:FilenameFilterjava.io.FilenameFilter接口,用于过滤文件名称

    抽象方法:

                           boolean accept(File dir, String name)

          参数:

              File dir:构造方法传递的被遍历的目录

              String name:使用ListFiles方法遍历目录,获取每一个文件/文件夹的名称。

注意: 

        两个过滤器接口没有实现类,需要重写实现类,重写过滤方法中accept方法,在方法中定义过滤规则。

 

字节流:

由硬盘读到内存,就是输入流,反过来就是输出流;也就是IO流。

java.io.OutputStream 抽象类是表示字节输出流的所有类的超类。定义的一些共性的方法:

public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输
出到此输出流。
public abstract void write(int b) :将指定的字节输出流。

FileOutputStream类:文件字节输出流

作用:把内存中的数据写入到硬盘的文件中

构造方法:

          public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
           public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件

     参数:写入数据的目的地

作用:

       1、创建一个FileOoutputStream对象

        2、会根据构造方法中传递的文件/文件路径,创建一个空的文件

        3、会把FileOutputStream对象指向创建好的文件。
使用步骤:

       1、创建一个FileOoutputStream对象,构造方法中传递写入数据的目的地

       2、调用FileOoutputStream对象方法,write,把数据写入到文件中

       3、释放资源(使用完毕,将内存清空,close方法)

注:如果写的第一个字节是正数(0~127),那么会显示查询ASCII码

       如果写的第一个字节是负数,那么第一个字节会和第二个字节组成一个中文显示,查询系统默认的码表(GBK)

追加写:使用两个参数的构造方法即可,如下:

public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的
文件。
public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。

参数:

      String name,File file:写入数据的目的地

       boolena append:追加写开关,true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据

                                                        flase:创建一个新文件,覆盖源文件

字节输入流:

java.io.InputStream 抽象类是表示字节输入流的所有类的超类

共用方法:

public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
public abstract int read() : 从输入流读取数据的下一个字节。
public int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。

java.io.FileInputStream 类继承了InputStream类

作用:把硬盘文件中的数据,读取到内存中

构造方法:

FileInputStream(File file) ;
FileInputStream(String name) ;

参数: 读取文件的数据源

           String name;文件路径

            File file:文件

构造方法作用:

        1、会创建一个FileInputStream对象

         2、会把FileInputStream对象,指定构造方法中要读取文件

使用步骤:

        1、创建FileInputStream对象,构造方法绑定要读取数据源

         2、使用FileInputStream对象中的方法read()读取文件

         3、释放资源

注:字节流,读取中文 utf-8编码占用3个字节,GBK占用2个字节

 

字符流:

java.io.Reader:字符流入流,是字符输入流的最顶层父类,定义了一些共性的成员方法,是一个抽象类。

共性的成员方法:

public int read() :读了单个字符并返回

public int read(char[] cbuf):一次读取多个字符,将字符读入数组

void close():关闭该流并释放与之关联的所有资源

FileReader类:文件字符输入流

java.io.FileReader extenders InputStreamReader extends Reader

作用:

      把硬盘文件中的数据以字符的方式读取到内存中

构造方法:

FileReader(File file) : 
FileReader(String fileName) : 

参数:

       String fileName:文件路径

       File file:一个文件
作用:

      1、创建一个FileReader对象

      2、会把FileReader对象指向要读取的文件

使用步骤:

      1、创建一个FileReader对象,构造方法中绑定要读取的数据源

      2、使用FileReader对象的方法read读取文件

       3、释放资源 

 

字符输出流:字符输出流

java.io.Writer是所有字符输出流最顶层的父类,是一个抽象类

共性成员方法

void write(int c) 
void write(char[] cbuf) 
abstract void write(char[] cbuf, int
void write(String str) 
void write(String str, int off, int le
void flush() 
void close()  

FileWriter类:文件字符输出流

作用:把内存中字符数据写入到文件中
java.io.FileWriter externds OutputStreadWriter extends Writer

构造方法:

FileWriter(File file) :
FileWriter(String fileName)
参数:写入数据的目的地

        File file:一个文件

        String fileName文件路径

构造方法作用;

        1、会创建一个FileWriter对象

        2、会根据构造方法中传递的文件/文件的路径,创建文件

        3、会把FileWriter对象指向创建好的文件。

字符输出流的使用步骤:

      1、创建FileWriter对象,构造方法中给绑定要写入数据的目的地

       2、使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程),与字节写入主要区别

       3、使用FileWriter中的方法Flush,把内存缓冲区中的数据,刷新到文件中

        4、释放资源close(会先把内存缓冲区中的数据刷新到文件中)

flush与close方法区别:

flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
 

写字符数据其他方法:   

//写数组

write(char[] cbuf) 写入字符数组

write(char[] cbuf, int off, int len):写入字符数组的某一部分,off数组开始索引,len写字符个数

 

//写字符串

write(String str) //写入字符串

write(String str, int off, int len)//写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
 

续写和换行:使用两个参数的构造方法即可。

   FileWriter(String fileName,boolean append)

   FileWriter(File file,boolean append)

    参数:

           String fileName ,File file:写入数据的目的地

            boolean append:续写开关,true:不会创建新的文件覆盖源文件,flase创建新的文件覆盖源文件。

jdk7与jdk9新特性:优化try catch变为try-with-resource,即程序结束后,关闭对象

                     JDK7                                                                                        JDK9,把对象的定义可以放在了外面,更符了程序的写法。

try (创建流对象语句,如果多个,使用';'隔开) {                                         // 被final修饰的对象
  // 读写数据                                                                                            final Resource resource1 = new Resource("resource1");
  } catch (IOException e) {                                                                      // 普通对象
      e.printStackTrace();                                                                          Resource resource2 = new Resource("resource2");
 }                                                                                                             // 引入方式:创建新的变量保存
                                                                                                               try (Resource r1 = resource1;
                                                                                                                Resource r2 = resource2) {
                                                                                                                  // 使用对象
                                                                                                                  }
 

属性集:

java.util.Properties 集合 extends Hashtable<k,v> implements Map<k,v>

Properties类表示 了一个持久的属性集。Properties 可以保存在流中或从流中加载

Properties 集合是一个唯一个和IO流相结合的集合。

           可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储

            可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

属性列表中每个键及对应的值都是一个字符串

    Properties集合是一个双列集合,key和value默认都是字符串。

    Properties有一些操作字符串的特有方法:

                  public Object setProperty(String key, String value) : 调用Hashtable的方法put
                  public String getProperty(String key) :通过Key找到value值,此方法相当于Map集合中的get(key)方法
                   public Set<String> stringPropertyNames() :返回此属性集合中的键集,其中该键及其对应的值是字符串,相当于Map集合中的keySet方法。
 

store方法:把集合中的临时数据,持久化写入到硬盘中存储

           void store(OutputStream out,String comments)

           void store(Writer writer,String comments)

            参数:

                   OutputStream out,字节输出流,不能写入中文

                   Writer writer,字符输出流,可以写中文

                   String comments:注释,用来解释说明保存文件是做什么用的,注释不能使用中文默认是Unicode编码。一般可以不加也就是用“ ”空字符串。

使用步骤:

             1、创建Properties集合对象,添加数据

              2、创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地

              3、使用Properties集合中的方法store,把集合中的临时数据持久写入硬盘

              4、释放资源
 

load方法:键值对文件读取到集合中使用

常用方法:

public void load(InputStream inStream)

public void load(Reader reader)
参数:

InputStream inStream:字节输入流,不能读取含有中文的键值对

Reader reader:字符输入流,能读取含有中文的键值对

使用步骤:

      1、创建Properties集合对象

       2、使用Properties集合对象中的方法load读取保存键值对的文件

       3、遍历Properties集合

   注意:

            1、存储键值对的文件中,键与值默认连接符号可以使用=,空格(其他符号)

             2、键值对文件可以使用#进行注释,被注释的键值对不会再被读取

             3、键值对文件,键与值都是字符串,不可再加引号

 

缓冲流:基本的流对象基础之上,相当于是对基本流对象的一种增强

原理:是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO
次数,从而提高读写的效率

java.io.BufferedOutputStream extends OutpuStream,所以父类的成员方法也适用,参见以上

BufferedOutputStream字节缓冲输出流

构造方法:

BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

BufferedOutputStream(OutputStream out, int size)  创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

参数:

        OutputStream out:字节输出流

                                      我们可以传递FileOutputStreadm,缓冲流会给FileOutputStreadm增加一个缓冲区,提高FileOutputStreadm的写入效率

         int size:指定缓冲流内部缓冲区的大小,不指定默认

使用步骤:

           1、创建FileOutputStreadm对象,构造方法中绑定要输出 的目的地

            2、创建FileOutputStreadm对象,构造方法中传递FileOutputStreadm对象,提高FileOutputStreadm对象效率

            3、使用FileOutputStreadm对象中的方法write,把数据写入到缓冲区中

            4、使用FileOutputStreadm对象中的方法flush,把内部缓冲区中的数据,刷新到文件中

             5、释放资源 ,调用close方法(会调用flush方法刷新数据,所以4步可省)

 

BufferedInputStream extends InputStream

字节缓冲输入流:继承父类的方法,详见以上《字节输入流共性方法》

构造方法:

BufferedInputStream(InputStream in)创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

BufferedInputStream(InputStream in, int size)创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用

参数:

        InputStream in:字节输入流

         int size:指定缓冲流内部缓冲区的大小,不指定默认

使用步骤:

          1、创建FileInputStream对象,构造方法中绑定要读取的数据源

           2、创建BufferedInputStream对象,构造方法中传递FileInputStreadm对象,提高FileInputStreadm对象的读取效率

           3、使用BufferedInputStream对象中的方法read,读取文件

            4、释放资源,关闭BufferedInputStream对象即可自动关闭FileInputStream对象

 

字符输出流:java.io.BufferedWriter extends Writer ,继承父类的共性成员方法

构造方法:

BufferedWriter(Writer out)创建一个使用默认大小输出缓冲区的缓冲字符输出流。

BufferedWriter(Writer out, int sz)创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

参数:

     Writer out:字符输出流,可以传递FileWriter,缓冲流会给FileWriter增加一个缓冲区。

      int sz:指定缓冲区的大小。不写执行默认

特有的成员方法:

      void newLine():写入一个行分隔符,会根据不同的操作系统,获取不同的行分隔符。即换行符符号

使用步骤:

             1、创建字符缓冲输出流对象,构造方法中传递字符输出流

              2、调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中

               3、调用字符缓冲输出流中的方法flush,把内存中的数据,刷新到文件中

                4、释放资源

 

字符缓冲输入流:java.io.BufferedReader extends Reader,继承父类共性方法,见以上

构造方法

BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int sz)创建一个使用指定大小输入缓冲区的缓冲字符输入流

参数:

       Reader in:字符输入流,可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高读取效率

特有成员方法: 

  String readLine():读取一个文本行,读取一行数据。行的终止符号:通过下列字符之一即可认为某行已经终止换行(“\n”),回车(“\r”),换行回车(“\r\n”).

返回值:

    包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

使用步骤:

     1、创建缓冲输入流对象,构造方法中传递字符输入流

     2、使用字符缓冲输入流对象中的方法read/readLine读取文本

     3、释放资源

 

转换流:

字符编码:一套自然语言的字符与二进制数之间的对应规则
字符集:一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

             ASCII字符集:美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位bits)表示一个字符,共256字符,方便支持欧洲常用字符。
            ISO-8859-1字符集:拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。使用单字节编码,兼容ASCII编码。

            GBxxx字符集:

                                 GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。

                                GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。

                                GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

Unicode字符集 :Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码

                         UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。
1. 128个US-ASCII字符,只需一个字节编码。
2. 拉丁文等字符,需要二个字节编码。
3. 大部分常用字(含中文),使用三个字节编码。
4. 其他极少使用的Unicode辅助字符,使用四字节编码。

 

转换流

java.io.OutputStreamWriter extends Writer:字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。继承自父类的共性方法:详见writer方法

构造方法:

OutputStreamWriter(OutputStream out) : 创建一个使用默认字符集的字符流。
OutputStreamWriter(OutputStream out, String charsetName) : 创建一个指定字符集的字符流

参数:

       OutputStream out:字节输出流,可以用来写转换之后的字节到文件中

       String charsetName:指定的编码表名称,不区分大小写。可以是utf-8/gbk,不指定使用utf-8

使用步骤:

            1、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称

             2、使用OutputStreamWriter对象中的方法Write,把字符转换为字节存储缓冲区中(编码)

              3、使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)

              4、释放资源 

 

java.io.InputStreamReader extends Reader是从字节流到字符流的桥梁:它使用指定的charset读取字节并将其解码为字符,继承其父类共性的方法:详见Reader方法

构造方法:

InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流。
参数:

       InputStream in:字节输入流,用来读取文件中保存的字节

       String charsetName:指定的编码表名称,不区分大小写。可以是utf-8/gbk,不指定使用utf-8

使用步骤:

1、创建InputStreamReade对象,传递字节输入流和指定的编码表名称

2、使用InputStreamReade对象中的方法read读取文件

3、释放资源

注意事项:

             构造方法中指定的编码表名称和文件的编码相同,否则会发生乱码

 

序列化与反序列化

把对象以流 的方式写入到文件中保存,叫写对象,也叫对象的序列化,对象转为字节

把文件中保存的对象,以流的方式读出来,叫做读对象,也叫对象的反序列化,字节重构为对象

 

java.io.ObjectOutputStream extends OutputStream对象序列化流

构造方法:

public ObjectOutputStream(OutputStream out) : 创建一个指定OutputStream的ObjectOutputStream。

参数:

        OutputStream out字节输出流

特有的成员方法:void writeObject(Object obj)将指定的对象写入ObjectOutputStream.

使用步骤:

             1、 创建ObjectOutputStream对象,构造方法中传递字节输出流

             2、使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中

              3、释放资源

注:

序列化与反序列化会抛出 NotSerializableException 异常。类通过实现jjava.io.Serializable 接口以启用其序列化功能。Serializable接口也叫标记型接口。当实现此接口时,会给类添加一个标记,当进行序列化与反序列化时会检测是否有这个标记,有就可以序列化,没有就会抛出异常。

Serializable  接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID  该版本号的目的在于验证序列化的对象和对应类是否版本匹配。可以查看Jdk使用手册,可以显式的声明,static final long serialVersionUID=XXL。这样无论是否有class 文件更新都会读出反序列化流。

 

java.io.ObjectInputStream extends InputStream对象反序列化流

构造方法:

public ObjectInputStream(InputStream in) : 创建从指定InputStream读取的ObjectInputStream。

参数:

       InputStream in:字节输入流

特有的成员变量方法:

Object readObject()//从ObjectInputStream读取对象

使用步骤:

             1、创建ObjectInputStream对象,构造方法中传递字节输入流

              2、使用ObjectInputStream对象中的方法readObject读取保存对象的文件

              3、释放资源 

              4、使用读出来的对象(打印)

注:

readObject方法声明抛出了ClassNotFoundException  异常(class 文件找不到异常),此异常不属于IO异常。需要单独抛出或其他处理。

 

transient关键字:瞬态关键字

被transient修饰的变量不能被序列化。

 

打印流:java.io.PrintStream 类能够方便地打印各种数据类型的值

printStream特点:

                        1、只负责数据的输出,不负责数据的读取

                        2、与其他输出流不同,printStream永远不会抛出IOException

                        3、有特有的方法,print,printfln,都可以输出任意数据类型的值

构造方法:PrintStream extends OutputStream 继承父类的成员方法,详见以上

public PrintStream(String fileName) : 输出的目的地是一个文件路径。

public PrintStream(File file) :输出的目的地是一个文件

public PrintStream(OutputStream out) :输出的目的地是一个字节输出流

注意事项:

         如果使用父类的write方法写数据,那么查看数据的时候会查询编码表,若使用特有的方法print/println,写出来的数据原样输出。

改变输出语句的目的地(打印流的方向,也就是C语言,打印到文件)

使用System.setOut方法改变,变为参数中传递的打印流的目的地

    static void setOut(PrintStream out)//重新分配“标准”输出流

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

guangod

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

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

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

打赏作者

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

抵扣说明:

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

余额充值