对ext2/ext3文件系统C语言读取编程示例

本文深入讲解ext2/ext3文件系统的内部结构,包括block、block group、group descriptor和super block,以及如何通过C语言进行编程读取这些信息。介绍了block的大小、block group的组成、inode的数据存储位置,以及超级块中的关键字段,为初学者提供了理解硬盘数据结构的基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文意在让初学者对于硬盘内的数据结构有一个基本的理解……

 

ext2 文件系 ,硬 分区首先被划分 一个个的 block ,一个 ext2 文件系 上的 block 都是一 大小的,但是 于不同的 ext2 文件系 block 的大小可以有区 典型的 block 大小是 1024 bytes 或者 4096 bytes 个大小在 ext2 文件系 候被决定,它可以由系 管理 指定,也可以由文件系 建程序根据硬 分区的大小,自 动选择 一个 合理的 blocks 被聚在一起分成几个大的 block group block group 中有多少个 block 是固定的。                     

block group 都相 对应 一个 group descriptor group descriptor 被聚在一起放在硬 分区的 开头 部分,跟在 super block 的后面。所 super block ,我 下面 到。在 descriptor 当中有几个重要的 block 。我 们这 里所 block ,就是指硬 分区上的 block 号数,比如,指 值为 0 ,我 它是指向硬 分区上的 block 0 ;指 值为 1023 ,我 它是指向硬 分区上的 block 1023 注意到,一个硬 分区上的 block 数是从 0 始的,并且 个硬 分区来 是全局性 的。

block group group descriptor 中,其中有一个 block 指向 block group block bitmapblock bitmap 中的 bit 表示一个 block ,如果 bit 0 ,表示 block 中有数据,如果 bit 1 表示 block 是空 的。注意, block bitmap 本身也正好只有一个 block 大小。假 block 大小 S bytes ,那 block bitmap 当中只能 记载 8*S block 的情况(因 一个 byte 等于 8 bits ,而一个 bit 对应 一个 block )。 也就是 ,一个 block group 最多只能有 8*S*S bytes 这么 大。

block group group descriptor 中另有一个 block 指向 inode bitmap bitmap 也是正好有一个 block 大,里面的 一个 bit 对应 一个 inode 上的一个 inode 大体上相 对应 于文件系 上的一个文件或者目 inode ,我 下面 步讲 到。

block group descriptor 中另一个重要的 block ,是指向所 inode table inode table 就不止一个 block 大了。 inode table 就是 block group 中所聚集到的全部 inode 放在一起形成的。

一个 inode 当中 记载 的最 关键 的信息,是 inode 中的用 数据存放在什 地方。 在前面提到,一个 inode 大体上相 对应 于文件系 中的一个文件,那 文件的内容存放在什 地方, 就是一个 inode 要回答的 问题 。一个 inode 提供一系列的 block ,来回答 问题 block 指向的 block ,里面就存放了用 文件的内容。

在我 一下。硬 分区首先被分 好多个 block block 聚在一起,被分成几 ,也就是 block group block group 都有一个 group descriptor 。所有 descriptor 被聚在一起,放在硬 分区的 开头 部分,跟在 super block 的后面。从 group descriptor 可以通 block ,找到 block group inode table block bitmap 等等。从 inode table 里面,我 就可以看到一个个的 inode 了。从一个 inode ,我 它里面的 block ,就可以 而找到存放用 数据的那些 block 。我 们还 要提一下, block 不是可以到 乱指的。一个 block group block bitmap inode bitmap 以及 inode table ,都依次存放在 block group 开头 部分,而那些存放用 数据的 block 跟在它 的后面。 一个 block group 束后,另一个 block group 又跟着 始。

http://www.ibm.com/i/v14/rules/blue_rule.gif

详细 的布局情况

Super Block

ext2 文件系 super block ,就是硬 分区 开头 开头 的第一个 byte byte 0 )从 byte 1024 始往后的一部分数据。由于 block size 最小是 1024 bytes ,所以 super block 可能是在 block 1 中(此 block 的大小正好是 1024 bytes ),也可能是在 block 0 中。

分区上 ext3 文件系 super block 详细 情况如下。其中 __u32 是表示 unsigned 符号的 32 bits 的数据 型,其余 推。 Linux 内核中所用到的数据 型,如果是 开发 user-space )的程序,可以根据具体 算机平台的情况,用 unsigned long 等等来代替。下面列表中 fragments 的部分可以忽略,Linux 上的 ext3 文件系 并没有 实现 fragments 个特性。另外要注意,ext3 文件系 在硬 分区上的数据是按照 Intel Little-endian 格式存放的,如果是在 PC 以外的平台上 开发 ext3 的程序,要特 注意 一点。如果只是在 PC 上做 开发 ,倒不用特 注意。

struct ext3_super_block {

/*00*/ __u32 s_inodes_count;      /* inodes */

       __u32 s_blocks_count;      /* blocks */

       __u32 s_r_blocks_count;    /* 保留的 blocks */

       __u32 s_free_blocks_count; /* blocks */

/*10*/ __u32 s_free_inodes_count; /* inodes */

       __u32 s_first_data_block;  /* 第一个数据 block */

       __u32 s_log_block_size;    /* block 的大小 */

       __s32 s_log_frag_size;     /* 可以忽略 */

/*20*/ __u32 s_blocks_per_group;  /* block group block 数量 */

       __u32 s_frags_per_group;   /* 可以忽略 */

       __u32 s_inodes_per_group;  /* block group inode 数量 */

       __u32 s_mtime;              /* Mount time */

/*30*/ __u32 s_wtime;             /* Write time */

       __u16 s_mnt_count;         /* Mount count */

       __s16 s_max_mnt_count;     /* Maximal mount count */

       __u16 s_magic;             /* Magic */

       __u16 s_state;             /* File system state */

       __u16 s_errors;            /* Behaviour when detecting errors */

       __u16 s_minor_rev_level;   /* minor revision level */

/*40*/ __u32 s_lastcheck;         /* time of last check */

       __u32 s_checkinterval;     /* max. time between checks */

       __u32 s_creator_os;        /* 可以忽略 */

       __u32 s_rev_level;         /* Revision level */

/*50*/ __u16 s_def_resuid;        /* Default uid for reserved blocks */

       __u16 s_def_resgid;        /* Default gid for reserved blocks */

       __u32 s_first_ino;         /* First non-reserved inode */

       __u16 s_inode_size;        /* size of inode structure */

       __u16 s_block_group_nr;    /* block group # of this superblock */

       __u32 s_feature_compat;    /* compatible feature set */

/*60*/ __u32 s_feature_incompat;  /* incompatible feature set */

       __u32 s_feature_ro_compat; /* readonly-compatible feature set */

/*68*/ __u8  s_uuid[16];          /* 128-bit uuid for volume */

/*78*/ char  s_volume_name[16];   /* volume name */

/*88*/ char  s_last_mounted[64];  /* directory where last mounted */

/*C8*/ __u32 s_algorithm_usage_bitmap; /* 可以忽略 */

       __u8  s_prealloc_blocks;        /* 可以忽略 */

       __u8  s_prealloc_dir_blocks;    /* 可以忽略 */

       __u16 s_padding1;               /* 可以忽略 */

/*D0*/ __u8  s_journal_uuid[16]; /* uuid of journal superblock */

/*E0*/ __u32 s_journal_inum;     /* 日志文件的 inode 号数 */

       __u32 s_journal_dev;      /* 日志文件的 设备 */

       __u32 s_last_orphan;      /* start of list of inodes to delete */

/*EC*/ __u32 s_reserved[197];    /* 可以忽略 */

};

可以看到,super block 一共有 1024 bytes 大。在 super block 中,我 第一个要 心的字段是 magic 名, ext2 ext3 文件系 个字段的 值应该 正好等于 0xEF53 如果不等的 ,那 么这 个硬 分区上肯定不是一个正常的 ext2 ext3 文件系 。从 里,我 也可以估 到, ext2 ext3 的兼容性一定是很 的,不然的 Linux 内核的 开发 应该 ext3 文件系 一个 magic 名才

super block 中另一个重要的字段是 s_log_block_size 。从 个字段,我 可以得出真正的 block 的大小。我 把真正 block 的大小 BB = 1 << (s_log_block_size + 10) 位是 bytes 例来 ,如果 个字段是 0 ,那 block 的大小就是 1024 bytes 正好就是最小的 block 大小;如果 个字段是 2 ,那 block 大小就是 4096 bytes 里我 就得到了 block 的大小 一非常重要的数据。

Group Descriptors

们继续 往下,看跟在super block 后面的一堆group descriptors 。首先注意到super block 是从 byte 1024 始,一共有1024 bytes 大。而 group descriptors 是从super block 后面的第一个 block 始。也就是 ,如果 super block 是在block 0 ,那 group descriptors 就是从 block 1 始;如果 super block 是在 block 1 ,那 group descriptors 就是从 block 2 始。因 super block 一共只有 1024 bytes 大,所以不会超出一个 block 界。如果一个 block 正好是 1024 bytes 大的 ,我 看到 group descriptors 就是 跟在 super block 后面的了,没有留一点空隙。而如果一个 block 4096 bytes 大的 ,那 group descriptors (从 byte 4096 始)和 super block 尾之 ,就有一定的空隙(4096 - 2048 bytes )。

分区上一共有多少个 block group ,或者 一共有多少个 group descriptors 要在 super block 中找答案。super block 中的 s_blocks_count 记录 了硬 分区上的 block 数,而 s_blocks_per_group 记录 group 中有多少个 block 然,文件系 上的 block groups 数量,我 把它 GG = (s_blocks_count - s_first_data_block - 1) / s_blocks_per_group + 1 要减去 s_first_data_block ,因 s_blocks_count 是硬 分区上全部的 block 的数量,而在 s_first_data_block 之前的 block 是不 block group 管的,所以当然要减去。最后 又要加一, 是因 尾巴上可能多出来一些 block block 要把它划在一个相 对较 小的 group 里面。

注意,硬 分区上的所有 group descriptors 要能塞在一个 block 里面。也就是 groups_count * descriptor_size 小于等于 block_size

知道了硬 分区上一共有多少个 block group ,我 就可以把 这么 多个 group descriptors 出来了。先来看看 group descriptor 是什 么样 子的。

struct ext3_group_desc

{

  __u32 bg_block_bitmap;      /* block 指向 block bitmap */

  __u32 bg_inode_bitmap;      /* block 指向 inode bitmap */

  __u32 bg_inode_table;       /* block 指向 inodes table */

  __u16 bg_free_blocks_count; /* blocks */

  __u16 bg_free_inodes_count; /* inodes */

  __u16 bg_used_dirs_count;   /* 录计 */

  __u16 bg_pad;               /* 可以忽略 */

  __u32 bg_reserved[3];       /* 可以忽略 */

};

group descriptor 32 bytes 大。从上面,我 看到了三个 关键 block 三个 关键 block ,我 在前面都提到 了。

Inode

前面都准 好了以后,我 们现 于可以 取文件了。首先要 的,当然是文件系 的根目 。注意, 里所 的根目 ,是相 一个文件系 或者 分区而言的,它并不一定是整个 Linux 操作系 上的根目 里的 root 存放在一个固定的 inode 中, 就是文件系 上的 inode 2 。需要提到 inode 数同 block 数一 ,也是全局性 的。 里需要特 注意的是, inode 数是从 1 始的,而前面我 提到 block 数是从 0 始, 个不同在 开发 程序的 候要特 留心。( 一奇怪的 inode 数方法,曾 经让 本文作者大 伤脑 筋。)

,我 先来看一下得到一个 inode 号数以后,怎 样读 inode 中的用 数据。在 super block 中有一个字段 s_inodes_per_group 记载 block group 中有多少个 inode 。用我 得到的 inode 号数除以 s_inodes_per_group ,我 就知道了我 要的 inode 是在哪一个 block group 里面, 个除法的余数也告 ,我 要的 inode block group 里面的第几个 inode ;然后,我 可以先找到 block group group descriptor ,从 descriptor ,我 找到 group inode table ,再从 inode table 找到我 要的第几个 inode ,再以后,我 就可以 inode 中的用 数据了。

个公式是 这样 的:block_group = (ino - 1) / s_inodes_per_group ino 就是我 inode 号数。而 offset = (ino - 1) % s_inodes_per_group offset 就指出了我 要的 inode block group 里面的第几个 inode

找到 inode 之后,我 来具体的看看 inode 是什 么样 的。

struct ext3_inode {

  __u16 i_mode;    /* File mode */

  __u16 i_uid;     /* Low 16 bits of Owner Uid */

  __u32 i_size;    /* 文件大小, 位是 byte */

  __u32 i_atime;   /* Access time */

  __u32 i_ctime;   /* Creation time */

  __u32 i_mtime;   /* Modification time */

  __u32 i_dtime;   /* Deletion Time */

  __u16 i_gid;     /* Low 16 bits of Group Id */

  __u16 i_links_count;          /* Links count */

  __u32 i_blocks;               /* blocks */

  __u32 i_flags;                /* File flags */

  __u32 l_i_reserved1;           /* 可以忽略 */

  __u32 i_block[EXT3_N_BLOCKS]; /* block */

  __u32 i_generation;           /* 可以忽略 */

  __u32 i_file_acl;             /* 可以忽略 */

  __u32 i_dir_acl;              /* 可以忽略 */

  __u32 i_faddr;                /* 可以忽略 */

  __u8  l_i_frag;                /* 可以忽略 */

  __u8  l_i_fsize;              /* 可以忽略 */

  __u16 i_pad1;                 /* 可以忽略 */

  __u16 l_i_uid_high;           /* 可以忽略 */

  __u16 l_i_gid_high;           /* 可以忽略 */

  __u32 l_i_reserved2;          /* 可以忽略 */

};

看到在 inode 里面可以存放 EXT3_N_BLOCKS= 15 这么 多个 block 。用 数据就从 block 里面 得。15 blocks 不一定放得下全部的用 数据,在 ext3 文件系 采取了一 构。 这组 15 block 的前 12 个是所 direct blocks ,里面直接存放的就是用 数据。第 13 block ,也就是所 indirect block ,里面存放的全部是 block block 指向的 block 才被用来存放用 数据。第 14 block 是所 double indirect block ,里面存放的全是 block block 指向的 block 也被全部用来存放 block ,而 block 指向的 block ,才被用来存放用 数据。第 15 block 是所 triple indirect block ,比上面 double indirect block 又多了一 block 。作 为练习 者可以 算一下, 这样 的分 层结 构可以使一个 inode 中最多存放多少字 的用 数据。 算所需的信息是否已 缺少哪一个 关键 数据?)

                                           

一个 inode 里面 实际 有多少个 block 是由 inode 字段 i_size 再通 过计 算得到的。i_size 记录 的是文件或者目 实际 大小,用它的 除以 block 的大小,就可以得出 inode 一共占有几个 block 注意上面的 i_blocks 字段,粗心的 者可能会以 一字段 记录 了一个 inode 实际 用到多少个 block ,其 不是的。那 么这 一字段是干什 用的呢, 者朋友 可以借 个机会,体 一下 阅读 Linux 内核源代 趣。 ;-)

文件系 的目 录结

在我 可以 inode 的内容了,再往后,我 将要 取文件系 上文件和目 的内容。 取文件的内容,只要把相 inode 的内容全部 出来就行了;而目 只是一 固定格式的文件, 个文件按照固定的格式 记录 了目 中有哪些文件,以及它 的文件名,和 inode 号数等等。

struct ext3_dir_entry_2 {

  __u32 inode;    /* Inode 号数 */

  __u16 rec_len;  /* Directory entry length */

  __u8  name_len; /* Name length */

  __u8  file_type;

  char  name[EXT3_NAME_LEN]; /* File name */

};

上面用到的 EXT3_NAME_LEN 255 。注意,在硬 分区上的 dir entry 不是固定 度的, dir entry 度由上面的 rec_len 字段

简单代码:

#include<stdio.h>

#define __u32  unsigned long

#define __u16  unsigned short

#define __u8   unsigned  char

 

struct ext3_super_block {

/*00*/ __u32 s_inodes_count;      /* inodes */

       __u32 s_blocks_count;      /* blocks */

       __u32 s_r_blocks_count;    /* 保留的 blocks */

       __u32 s_free_blocks_count; /* blocks */

/*10*/ __u32 s_free_inodes_count; /* inodes */

       __u32 s_first_data_block;  /* 第一个数据 block */

       __u32 s_log_block_size;    /* block 的大小 */

//      __s32 s_log_frag_size;     /* 可以忽略 */

/*20*/ __u32 s_blocks_per_group;  /* block group block 数量 */

       __u32 s_frags_per_group;   /* 可以忽略 */

       __u32 s_inodes_per_group;  /* block group inode 数量 */

       __u32 s_mtime;             /* Mount time */

/*30*/ __u32 s_wtime;             /* Write time */

       __u16 s_mnt_count;         /* Mount count */

//       __s16 s_max_mnt_count;     /* Maximal mount count */

       __u16 s_magic;             /* Magic */

       __u16 s_state;             /* File system state */

       __u16 s_errors;            /* Behaviour when detecting errors */

       __u16 s_minor_rev_level;   /* minor revision level */

/*40*/ __u32 s_lastcheck;          /* time of last check */

       __u32 s_checkinterval;     /* max. time between checks */

       __u32 s_creator_os;        /* 可以忽略 */

       __u32 s_rev_level;         /* Revision level */

/*50*/ __u16 s_def_resuid;        /* Default uid for reserved blocks */

       __u16 s_def_resgid;        /* Default gid for reserved blocks */

       __u32 s_first_ino;         /* First non-reserved inode */

       __u16 s_inode_size;        /* size of inode structure */

       __u16 s_block_group_nr;    /* block group # of this superblock */

       __u32 s_feature_compat;    /* compatible feature set */

/*60*/ __u32 s_feature_incompat;  /* incompatible feature set */

       __u32 s_feature_ro_compat; /* readonly-compatible feature set */

/*68*/ __u8  s_uuid[16];           /* 128-bit uuid for volume */

/*78*/ char  s_volume_name[16];   /* volume name */

/*88*/ char  s_last_mounted[64];  /* directory where last mounted */

                

/*C8*/ __u32 s_algorithm_usage_bitmap; /* 可以忽略 */

       __u8  s_prealloc_blocks;        /* 可以忽略 */

       __u8  s_prealloc_dir_blocks;    /* 可以忽略 */

       __u16 s_padding1;               /* 可以忽略 */

/*D0*/ __u8  s_journal_uuid[16]; /* uuid of journal superblock */

/*E0*/ __u32 s_journal_inum;     /* 日志文件的 inode 号数 */

       __u32 s_journal_dev;      /* 日志文件的 设备 */

       __u32 s_last_orphan;      /* start of list of inodes to delete */

/*EC*/// __u32 s_reserved[197];    /* 可以忽略 */

}ext3_block;

 

void Initial()

{

   FILE *fp;

   fp=fopen("myImage.img","rb");

   // 定位

   fseek(fp,1024,0);

  

 

/*00*/   fread(&(ext3_block.s_inodes_count),4,1,fp);       /* inodes */

         fread(&(ext3_block.s_blocks_count),4,1,fp);       /* blocks */

         fread(&(ext3_block.s_r_blocks_count),4,1,fp);   /* 保留的 blocks */

         fread(&(ext3_block.s_free_blocks_count),4,1,fp);  /* blocks */

/*10*/   fread(&(ext3_block.s_free_inodes_count),4,1,fp);  /* inodes */

         fread(&(ext3_block.s_first_data_block),4,1,fp);   /* 第一个数据 block */

         fread(&(ext3_block.s_log_block_size),4,1,fp);     /* block 的大小 */

 

         fseek(fp,4,1);                            /* 忽略 s_log_frag_size */

 

/*20*/   fread(&(ext3_block.s_blocks_per_group),4,1,fp);   /* block group block 数量 */

         fread(&(ext3_block.s_frags_per_group),4,1,fp);    /* 可以忽略 */

         fread(&(ext3_block.s_inodes_per_group),4,1,fp);   /* block group inode 数量 */

         fread(&(ext3_block.s_mtime),4,1,fp);              /* Mount time */

/*30*/   fread(&(ext3_block.s_wtime),4,1,fp);               /* Write time */

         fread(&(ext3_block.s_mnt_count),2,1,fp);          /* Mount count */

 

                              fseek(fp,2,1);                            /* 忽略 s_max_mnt_count */

 

         fread(&(ext3_block.s_magic),2,1,fp);              /* Magic */

                              fread(&(ext3_block.s_state),2,1,fp);              /* File system state */

         fread(&(ext3_block.s_errors),2,1,fp);             /* Behaviour when detecting errors */

         fread(&(ext3_block.s_minor_rev_level),2,1,fp);    /* minor revision level */

/*40*/   fread(&(ext3_block.s_lastcheck),4,1,fp);          /* time of last check */

                              fread(&(ext3_block.s_checkinterval),4,1,fp);      /* max. time between checks */

                              fread(&(ext3_block.s_creator_os),4,1,fp);         /* 可以忽略 */

                              fread(&(ext3_block.s_rev_level),4,1,fp);          /* Revision level */

/*50*/   fread(&(ext3_block.s_def_resuid),2,1,fp);         /* Default uid for reserved blocks */

                              fread(&(ext3_block.s_def_resgid),2,1,fp);         /* Default gid for reserved blocks */

                              fread(&(ext3_block.s_first_ino),4,1,fp);          /* First non-reserved inode */

                              fread(&(ext3_block.s_inode_size),2,1,fp);         /* size of inode structure */

                              fread(&(ext3_block.s_block_group_nr),2,1,fp);     /* block group # of this superblock */

                              fread(&(ext3_block.s_feature_compat),4,1,fp);     /* compatible feature set */

/*60*/   fread(&(ext3_block.s_feature_incompat),4,1,fp);   /* incompatible feature set */

                              fread(&(ext3_block.s_feature_ro_compat),4,1,fp);  /* readonly-compatible feature set */

/*68*/    fread(&(ext3_block.s_uuid),1,16,fp);              /* 128-bit uuid for volume */

                              fread(&(ext3_block.s_volume_name),1,16,fp);       /* volume name */

                              fread(&(ext3_block.s_last_mounted),1,64,fp);      /* directory where last mounted */

                              fread(&(ext3_block.s_algorithm_usage_bitmap),4,1,fp);

                              fread(&(ext3_block.s_prealloc_blocks),1,1,fp);

         fread(&(ext3_block.s_prealloc_dir_blocks),1,1,fp);

                              fread(&(ext3_block.s_padding1),2,1,fp);

                              fread(&(ext3_block.s_journal_uuid),1,16,fp);      /* uuid of journal superblock */

                              fread(&(ext3_block.s_journal_inum),4,1,fp);       /* 日志文件的 inode 号数 */

                              fread(&(ext3_block.s_journal_dev),4,1,fp);        /* 日志文件的 设备 */

                              fread(&(ext3_block.s_last_orphan),4,1,fp);        /* start of list of inodes to delete */

 

 

   printf("%20s  :  %-d/n","s_inodes_count",ext3_block.s_inodes_count);

   printf("%20s  :  %-d/n","s_blocks_count",ext3_block.s_blocks_count);

   printf("%20s  :  %-d/n","s_r_blocks_count",ext3_block.s_r_blocks_count);

   printf("%20s  :  %-d/n","s_free_blocks_count",ext3_block.s_free_blocks_count);

   printf("%20s  :  %-d/n","s_free_inodes_count",ext3_block.s_free_inodes_count);

   printf("%20s  :  %-d/n","s_first_data_block",ext3_block.s_first_data_block);

   printf("%20s  :  %-d/n","s_log_block_size",ext3_block.s_log_block_size);

   printf("%20s  :  %-d/n","s_blocks_per_group",ext3_block.s_blocks_per_group);

   printf("%20s  :  %-d/n","s_mtime",ext3_block.s_mtime);

   printf("%20s  :  %-d/n","s_wtime",ext3_block.s_wtime);

   printf("%20s   :  %-d/n","s_mnt_count",ext3_block.s_mnt_count);

   printf("%20s  :  %-x/n","s_magic",ext3_block.s_magic);

 

   int G = (ext3_block.s_blocks_count - ext3_block.s_first_data_block - 1) / ext3_block.s_blocks_per_group + 1;

 

   printf("%20s  :  %-d/n","block group",G);

 

   fclose(fp);

 

}

 

int main()

{

    Initial();

              return 0;

}


 

后面照葫芦画瓢,就不用教了吧。 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值