java io文件流序列化_Java 持久化操作之 --io流与序列化

1)File类操作文件的属性

1.File类的常用方法

f48dfdbeaeff6038dcb9cf05b20142ed.png

1.

文件的绝对完整路径:getAbsolutePath()

文件名:getName()

文件相对路径:getPath()

文件的上一级目录:getParent()

文件的大小为:length()

删除文件:delete()

具体操作请参考如下代码:

package text;

import java.io.File;

import java.util.Scanner;

/**

*

* @author: 房上的猫

*

* @time: 下午7:55:16

*

* @博客地址: https://www.cnblogs.com/lsy131479/

*

* 消费信息

*

*/

public class TextFile {

public static void main(String[] args)

{

try {

FileText();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public static void FileText() throws Exception

{

//1.实例化对象指定判断路径

File file=new File("D:\\TextFile\\A.txt");

//2.判断A.txt是否存在

if(file.exists())

{

//判断是否是文件夹

if(file.isDirectory())

{

System.out.println("这是一个文件夹");

}else

{

System.out.println("当前文件存在");

System.out.println("这是一个文件");

System.out.println("文件的绝对完整路径:"+file.getAbsolutePath());

System.out.println("文件名:"+file.getName());

System.out.println("文件相对路径:"+file.getPath());

System.out.println("文件的上一级目录:"+file.getParent());

System.out.println("文件的大小为:"+file.length());

Scanner input=new Scanner(System.in);

System.out.println("请按1删除此文件=======");

if(input.nextInt()==1)

{

boolean flog1= file.delete();

if(flog1)

{

System.out.println("删除成功");

}

}

}

}else

{

System.out.println("当前文件不存在---开始创建");

//3.不存在则创建新文件

boolean flog=file.createNewFile();

if(flog)

{

System.out.println("文件创建成功");

}

}

}

}

2)IO流(堵塞型io)

68f55954849831bae902772c8b0f4fb7.png

如何读写文件?

分析:流是指一连串流动的字符,是以先进先出方式发送信息的通道

输入/输出流于数据源:

dc745bb96a7fdc29a26a40f2e62552f1.png

java流的分类:

我们可以对它进行如下分类:

· 按处理的数据类型可分为字节流与字符流

· 按流的流向可分为输入流(in)与输出流(out)

· 按流的功能可分为节点流(Node)和过滤流(Filter)

在Java中,字节流一般适用于处理字节数据(诸如图片、视频),字符流适用于处理字符数据(诸如文本文件),但二者并没有严格的功能划分,因为有转换流的存在,使得对于数据的处理变得更加灵活。

1)字节流读写文件

一般用于处理字节数据,但字节流采用ASCII编码的,所以处理字符数据时容易出现中文乱码

1. 输入流

InputStream:此抽象类是表示字节输入流的所有类的超类(基类)

序号

方法描述

1

public final int read(byte[] r, int off, int len)throws IOException

从所包含的输入流中将 len 个字节读入一个字节数组中。如果len为-1,则返回已读字节数。

2

Public final int read(byte [] b)throws IOException

从所包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。

3

1. public final Boolean readBooolean()throws IOException,

2. public final byte readByte()throws IOException,

3. public final short readShort()throws IOException

4. public final Int readInt()throws IOException

从输入流中读取字节,返回输入流中两个字节作为对应的基本数据类型返回值。

4

public String readLine() throws IOException

从输入流中读取下一文本行。

所有字节输入流都是以此类发散出来的,但此类是一个抽象类,不可被实例化,所以实际编程过程中,都是使用它发散出来的一些子类,下面是输入流的关系图:

4a8ba7885ad30a1af7ca01088d8ab059.png

输入流最常用的就是FileInputStream类:

1-1文本文件的读取:用FileInputStream

该流用于从文件读取数据,它的对象可以用关键字 new 来创建。

·有多种构造方法可用来创建对象。

·可以使用字符串类型的文件名来创建一个输入流对象来读取文件:

·····InputStream f = new FileInputStream("C:/java/hello");

·也可以使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用 File() 方法来创建一个文件对象:

·····File f = new File("C:/java/hello");

·····InputStream out = new FileInputStream(f);

·创建了InputStream对象,就可以使用下面的方法来读取流或者进行其他的流操作。

字节流:

基类:InputStream     子类:FileInputStream

构造:

FileInputStream(File file)   ||   FileInputStream(String name)

f579b52b2dd44c98abdb260d8d470a24.png

方法:

read() 按字节读

read(byte[] b) 读到字节数组缓冲区,数组存满统一批次循环读取

read(byte[] b, int off, int len)  向数组存放时进行了限制,起始位置off和终止位置len

int  available()   表示当前还剩多少个字节未读取

4b01fb4d11f2ec5020c249b82de26c2c.png

注意:read方法返回 int 类型 返回读入字节数组的长度,如果读取到文件末尾的时候,则返回-1

代码演示按字节读取到控制台:

四步走:1.导入相关类   2.创建字节流对象   3.实现读取文本文件的数据   4.关闭文件流对象

测试文档:

使用Read()读取

废话不多说 举个栗子:

package text;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.FileInputStream;

public class FileInputStream01 {

public static void main(String[] args) {

//创建字节流对象

InputStream fls=null;

try {

fls=new FileInputStream("D://TextFile//A.txt");

//实现读取操作

int data;//存储读取的字节

while((data=fls.read())!=-1)

{

//System.out.print(data);//读取的是数字

System.out.print((char)data);//读取的是和文件一致

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

try {

if(fls!=null)

fls.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

修改代码使用Read(byte[] b)读取

int len;//存储读入数组的长度

byte[] wrods=new byte[1024];

while((len=fls.read(wrods))!=-1)

{

System.out.print(new String(wrods,0,len));//String构造方法 把字节byte[] 转换成字符串形式,0代表截取起始位置,len表示截取终止位置

}

结果与上述一致:

1. 输出流

OutputStream:此抽象类是表示字节输出流的所有类的超类(基类)

序号

方法描述

1

public final void write(byte[] w, int off, int len)throws IOException

将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流。

2

Public final int write(byte [] b)throws IOException

将指定的字节写入此字节数组输出流。

3

1. public final void writeBooolean()throws IOException,

2. public final void writeByte()throws IOException,

3. public final void writeShort()throws IOException,

4. public final void writeInt()throws IOException

这些方法将指定的基本数据类型以字节的方式写入到输出流。

4

Public void flush()throws IOException

刷新此输出流并强制写出所有缓冲的输出字节。

5

public final void writeBytes(String s) throws IOException

将字符串以字节序列写入到底层的输出流,字符串中每个字符都按顺序写入,并丢弃其高八位。

所有字节输出流都是以此类发散出来的,但此类是一个抽象类,不可被实例化,所以实际编程过程中,都是使用它发散出来的一些子类,下面是输出流的关系图:

9d5264fd3d9971e2475870115c251ff2.png

输出流最常用的就是FileOutputStream 类:

1-2文本文件的写入:用FileOutputStream

该类用来创建一个文件并向文件中写数据。

如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。

有两个构造方法可以用来创建 FileOutputStream 对象。

使用字符串类型的文件名来创建一个输出流对象:

OutputStream f = new FileOutputStream("C:/java/hello")

也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:

File f = new File("C:/java/hello");

OutputStream f = new FileOutputStream(f);

输出流:

基类:OutputStream

子类:FileOutputStream  ..............

构造:

19aa69cddb340b61c6aed322c8c0e51d.png

方法:

5c7831c4f27ca14d77490731dddcfe4f.png

废话不多说 举个栗子:

package text;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

public class FileoutputStream {

public static void main(String[] args) {

//创建输出字节流

OutputStream fls =null;

try {

//以File类对象作为参数,或 String name

//构造一个参数

//fls=new FileOutputStream(new File("D://TextFile//B.txt"));

//file - 为了进行写入而打开的文件。

//append - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处

fls=new FileOutputStream(new File("D://TextFile//B.txt"),true);

//声明要写入的内容

String name="我是测试字符串";

//将字符串转换为字节数组

byte[] words=name.getBytes();

//写入方法一

//fls.write(words);

//写入方法二

fls.write(words,0,words.length);

System.out.println("写入成功");

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

try {

fls.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

1-3文件读取和写入同步

废话不多说 举个栗子:

package text;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

public class FileoutputStream {

public static void main(String[] args) {

//创建输出字节流

OutputStream fls =null;

try {

//以File类对象作为参数,或 String name

//构造一个参数

//fls=new FileOutputStream(new File("D://TextFile//B.txt"));

//file - 为了进行写入而打开的文件。

//append - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处

fls=new FileOutputStream(new File("D://TextFile//B.txt"),true);

//声明要写入的内容

String name="我是测试字符串";

//将字符串转换为字节数组

byte[] words=name.getBytes();

//写入方法一

//fls.write(words);

//写入方法二

fls.write(words,0,words.length);

System.out.println("写入成功");

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

try {

fls.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

2)字符流读和缓冲流读文件

用BufferedReader 和 BufferedWriter读写文本文件//字符流

或 FileReader

字符编码:ASCII码   0~127  8位二进制数1个字节。  16位二进制数表示一个字符 两个字节

字符流:输入流

基类:Reader----FileReader

63980f09b79db5bd1169b8bc2c373908.png

构造:

0ebe7e7cc231bb850c12fbddbc61cbbd.png

常用方法:

1e9f388146f457d5df571694f04c666b.png

1)如果 使用字节流读取带有汉字的文件会怎么样那

package text;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.InputStream;

import java.io.FileInputStream;

public class FileInputStream01 {

public static void main(String[] args) {

//创建字节流对象

InputStream fls=null;

try {

fls=new FileInputStream("D://TextFile//A.txt");

//实现读取操作

int data;//存储读取的字节

while((data=fls.read())!=-1)

{

//System.out.print(data);//读取的是数字

//System.out.println("还剩:"+fls.available()+"字节未读取");

System.out.print((char)data);

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

try {

if(fls!=null)

fls.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

运行结果如下:

b4ddfe33cb453b9a9394dbbfe2b408fa.png

很明显出现了乱码

2)下面使用FileReader字符流 Read()读取文件,示例如下

package text;

/**

* 使用字符流读取文本文件

*

Title:FileReaderDemo

*

Description:

*

Company:

* @author MLQ

* @date 2018年3月7日 下午12:38:35

*/

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.io.Reader;

public class FileReaderDemo {

public static void main(String[] args) {

//创建一个字符流对象

Reader rd=null;

try {

rd=new FileReader("D://TextFile//A.txt");

int word;//就收读取的字符

while((word=rd.read())!=-1)

{

System.out.print((char)word);

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

if(rd!=null)

{

try {

rd.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

运行结果你会发现,乱码消失了

3)下面使用FileReader字符流 Read(char[] b)读取文件,示例如下

修改代码如下:

package text;

/**

* 使用字符流读取文本文件

*

Title:FileReaderDemo

*

Description:

*

Company:

* @author MLQ

* @date 2018年3月7日 下午12:38:35

*/

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.io.Reader;

public class FileReaderDemo {

public static void main(String[] args) {

//创建一个字符流对象

Reader rd=null;

StringBuffer sb=new StringBuffer();

try {

rd=new FileReader("D://TextFile//A.txt");

int word;//就收读取的字符

char[] ch=new char[1024];

while((word=rd.read(ch))!=-1)

{

sb.append(ch,0,word);

}

System.out.println(sb.toString());

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

if(rd!=null)

{

try {

rd.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

运行结果如下:

b932f053f2e3a1791aa73e4c7ef624dc.png

温馨提示:如果上述的代码 sb.append(ch,0,word)  只写数组的话,会把空格也会追加到 StringBuffer。读取文

件的时候最后可能没有写满数组

4)使用BufferedReader读取文本文件

(增强)

BufferedReader类是Reader类的子类

bufferedReader类带有缓冲区

按行读取内容的ReadLine()方法

实现步骤:

ab25bc313157ca3b43a9e13ee93dde53.png

构造:

439ce9507d055ae83bfea4d2735eb14e.png

方法:

75e1fca1fdfbdbf85aa1e0d4438b2393.png

演示代码如下:

package text;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.io.Reader;

import java.io.*;

public class BufferedReader01 {

public static void main(String[] args) {

//创建一个字符流对象

Reader rd=null;

//创建BufferedReader对象

BufferedReader bf=null;

StringBuffer sb=new StringBuffer();

try {

rd=new FileReader("D://TextFile//A.txt");

bf=new BufferedReader(rd);//传入Reader对象

String word=null;//接收返回值,读到末尾返回null

while((word=bf.readLine())!=null)

{

System.out.println(word);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally

{

if(rd!=null)

{

try {

rd.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(bf!=null)

{

try {

bf.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

运行结果如下:

54295d764090ace4804ba9932d30c60f.png

3)字符流读和缓冲流写文件

基类:Write    子类:FileWrite

cb0419954c23b7997ccd8a81c5061a75.png

构造:

d461307dd1be25e56ba32eb51d78a0e7.png

方法:

1dbe88357e1200597907ed2954179199.png

演示代码如下:

3-1)使用FileWrite字符流写入文档

package text;

import java.io.FileWriter;

import java.io.IOException;

import java.io.Writer;

public class FileWriter01 {

public static void main(String[] args) {

//创建写入字符流

Writer rd=null;

try {

rd=new FileWriter("D://TextFile//A.txt",true);

String s="我是写入测试编码";

rd.write(s);//写入文档

rd.flush();//刷新缓冲区

System.out.println("写入成功");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally

{

if(rd!=null)

{

try {

rd.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

3-2)使用BufferedWrite字符流写入文件

如何提高字符流写文本文件的效率?

解:使用FileWrite类与BufferReader类

BufferedWrite类是Write类的子类

BufferedWrite类带有缓冲区

步骤:

c4b8c61a0aa33155ada94ef065776b05.png

构造:

f83e18fffb1f7abab5cf913836bc73af.png

方法:

d411a3284d48170fd066578d87f262a4.png

代码演示如下:

package text;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.Reader;

import java.io.Writer;

public class BufferedWrite01 {

public static void main(String[] args) {

//创建FileWrite 和 BufferedWrite 对象

Writer wd=null;

BufferedWriter bw=null;

//创建FileReader 和 BufferedReader 对象

Reader ed=null;

BufferedReader br=null;

try {

wd=new FileWriter("D:\\TextFile\\A.txt");

bw=new BufferedWriter(wd);

bw.write("我是测试员");

bw.newLine();//换行符方法

bw.write("负责测试程序运行问题");

bw.flush();

System.out.println("成功写入");

//读取文本文件信息

ed=new FileReader("D:\\TextFile\\A.txt");

br=new BufferedReader(ed);

String word=null;

while((word=br.readLine())!=null)

{

System.out.println(word);

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

finally

{

if(wd!=null){

try {

wd.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(bw!=null){

try {

bw.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(ed!=null){

try {

ed.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(bw!=null){

try {

bw.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

4)使用数据流读写文件

二进制文件读写:

使用DataInputStream  和  DataOutputStream 读写二进制文件  //属于字节流

DataInputStream  类:

FileInputStream的子类

与FileInputStream类结合使用读取二进制文件

DataOutputStream 类:

FileOutputStream的子类

与FileOutputStream类结合使用写二进制文件

456ae159f15adf78e0c6175643e7fe21.png

DataOutputStream:

107117b1615904a82e69ee5a4730d32b.png

0a7f9c520efc88bf9bab4d192bf409d7.png

演示代码如下:

实现步骤:

481b28525596cf5adcde46a14b22ebb3.png

[

package text;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

@SuppressWarnings("unused")

public class DataInOutStream {

@SuppressWarnings("resource")

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

DataInputStream di=null;

DataOutputStream ds=null;

di=new DataInputStream(new FileInputStream("D://TextFile//dd.class"));

ds=new DataOutputStream(new FileOutputStream("D://TextFile//coty.class"));

int len;//接收读取的字节

while((len=di.read())!=-1)

{

ds.write(len);

}

System.out.println("执行完毕");

if(di!=null)

di.close();

ds.close();

}

}

3)序列化和反序列化

序列化和反序列化的过程

33c713d30946ddfe8f04ebfd5485be36.png

序列化的步骤:

1.实现 Serializable 接口

2.创建对象输出流

3.调用 writeObject()方法将对象写入文件

4.关闭对象输出流

使用集合保存对象,可以将集合中的所有对象序列化

序列化构造和常用方法

46dd3511865c1b4cf23baa37e6a6599b.png

1b5a3839fa02d06a09ea8b4dfe89ad42.png

反序列化构造和常用方法

eb524bae7140ed39deea17e49f849a88.png

1cc69823ea353a02753abb33ffe39a70.png

实现序列化 和 反序列化 演示代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package text;

import java.io.Serializable;

public class Student implements Serializable

{

/**

* 记录版本信息

*/

private static final long serialVersionUID = 224961941376318131L;

private String name;

private int age;

transient private String sex;

public Student(String name, int age, String sex) {

super();

this.name = name;

this.age = age;

this.sex = sex;

}

/**

* @return the name

*/

public String getName() {

return name;

}

/**

* @param name the name to set

*/

public void setName(String name) {

this.name = name;

}

/**

* @return the age

*/

public int getAge() {

return age;

}

/**

* @param age the age to set

*/

public void setAge(int age) {

this.age = age;

}

/**

* @return the sex

*/

public String getSex() {

return sex;

}

/**

* @param sex the sex to set

*/

public void setSex(String sex) {

this.sex = sex;

}

public void show()

{

System.out.println("我叫:"+this.getName()+"年龄:"+this.getAge()+"性别:"+this.getSex());

}

}

Student 类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package text;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

public class TextStudent {

@SuppressWarnings("unchecked")

public static void main(String[] args) {

//创建序列化对象

ObjectOutputStream xl=null;

//创建反序列化对象

ObjectInputStream xl1=null;

//初始化要序列化的对象

Map map=new HashMap();

Map map1=new HashMap();

Student stu=new Student("小明",18,"男");

Student stu1=new Student("小红",18,"女");

map.put(stu.getName(), stu);

map.put(stu1.getName(), stu1);

try {

xl=new ObjectOutputStream(new FileOutputStream("D://TextFile//xuliehua.bin"));

xl1=new ObjectInputStream(new FileInputStream("D://TextFile//xuliehua.bin"));

xl.writeObject(map);

System.out.println("写入成功");

//反序列化文件输出到控制台

map1=(Map)xl1.readObject();

Set key=map1.keySet();

Iterator l=key.iterator();

while(l.hasNext())

{

String keys=l.next();

map1.get(keys).show();

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

finally

{

if(xl!=null){

try {

xl.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(xl1!=null)

{

try {

xl1.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

测试类

提示:如果不希望Student类某一属性被序列化可使用 transient 修饰

biu ~biu ~ biu ~

注:最后在提一句:使用序列化操作时,一定要将准备序列化的类或数据声明为可序列化操作!!!!

e9b8991d7a703d9c84c667bc881e08ad.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值