Linux-管理文件权限和所有权
来源:互联网 发布:navicat如何连接mysql 编辑:程序博客网 时间:2024/06/05 00:18
本文转自:http://www.ibm.com/developerworks/cn/linux/l-lpic1-v3-104-5/
在本文中,了解通过文件、目录权限和所有权的正确使用控制文件访问。学习:
- 管理普通和特殊文件及目录的访问权限
- 使用访问模式,如 suid、sgid 和粘贴位(sticky bit),维护安全性
- 变更文件创建屏蔽
- 向组成员授予访问权限
先决条件
为了最有效地利用本系列中的文章,您应该具有基本的 Linux 知识,并需要准备一个 Linux 系统,用于练习本文介绍的命令。有时候不同版本的程序输出格式不同,因此您所得到的结果未必总是与这里所示的清单和图相同。
用户和组
我是谁?现在,您了解了 Linux 是一个多用户的系统,每个用户属于一个主要 组,也可能是附加组。也可以作为一个用户登录,然后使用 su
或者 sudo -s
命令变为另一个用户。Linux 的文件所有权和访问授权是与用户 id 和组密切相关的,所以我们要复习一下基本的用户和组信息。
如果没有切换到其他用户,您的 id 就是登录时的。如果切换到其他用户,在本文的大多数例子中,您的提示中就会包括您的用户 id。如果您的提示没有包括用户 id,可以使用 whoami
命令来检查您当前有效的 id。清单 1 显示了一些例子,说明了提示字符串(来自 PS1 环境变量)与本文中的其他例子不同。在提示字符串中包含您的 id 是一个有用的功能。
清单 1. 决定有效的用户 id
/home/ian$ whoamitom/home/ian$ exitexit$ whoamiian
我在什么组中?
类似的,您可以使用 groups
命令找出您在什么组中。使用 id
命令,您可以找出用户和组信息。添加一个用户 id 参数到 groups
或者 id
来查看该用户 id 的信息,而并非当前用户 id。查看 清单 2 中的示例。请注意,没有用户 id,id
命令也会显示 SELinux 上下文和基本 id 信息。
清单 2. 决策组成员
[ian@echidna ~]$ iduid=1000(ian) gid=1000(ian) groups=1000(ian),505(development),8093(editor)context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023[ian@echidna ~]$ id ianuid=1000(ian) gid=1000(ian) groups=1000(ian),8093(editor),505(development)[ian@echidna ~]$ groupsian development editor[ian@echidna ~]$ id tomuid=1012(tom) gid=1012(tom) groups=1012(tom),505(development)[ian@echidna ~]$ groups tomtom : tom development[ian@echidna ~]$ su tomPassword: [tom@echidna ian]$ groupstom development[tom@echidna ian]$ groups ianian : ian editor development
文件的所有权和权限
如果每个用户都有 id 并且是主要组的成员,那么 Linux 系统上的每个文件都有一个所有者和与其相关的组。
普通文件
使用 ls -l
命令显示所有者和组。
清单 3. 决定文件所有权
[ian@echidna ~]$ ls -l /bin/bash .bashrc helloworld.C -rw-r--r--. 1 ian ian 124 Mar 31 2010 .bashrc-rwxr-xr-x. 1 root root 943360 May 21 2010 /bin/bash-rw-rw-r--. 1 ian development 116 Nov 30 10:21 helloworld.C
在这个特殊的例子中,用户 ian 的 .bashrc 文件由他自己所有,并且属于 ian 的主要组。类似的,/bin/bash 由用户 root 所有,并且位于组 root。但是,helloworld.C 由用户 ian 所有,但是属于组 development。用户名和组名来自不同的名称空间,所以给定的名称可能同时是用户名和组名。事实上,很多版本默认为每个新用户创建一个匹配的组。
Linux 权限模型每个文件系统对象有 3 种类型。这些权限就是读(r),写(w)和执行(x)。写权限包括修改和删除对象的能力。此外,这些权限被分别指定给文件所有者、文件组成员和其他人。
回到清单 3 第一列,注意,它包括一个 11 个字符的字符串。这第 11 个字符是最近才添加的。我们稍后再讨论。第一个字母描述了对象的类型(-
在这个例子中表示普通文件),剩下的 9 个字母每三个字母为一组。第一组表示文件所有者的读、写和执行权限。-
表示相应的权限没有被授予。因此,用户 ian 就可以读和写 .bashrc 文件,但是不能执行它;而 root 可以读、写 和 执行 /bin/bash 文件。第二组表示文件组的读、写和执行权限。development 组的成员能够读或者写 ian 的 helloworld.C 文件,而其他人只能读。类似的,root 组中的成员和其他人能够读或者执行 /bin/bash 文件。
目录
目录和常规文件一样使用相同的权限标识,但是它们的翻译不同。目录的读权限允许用户使用该权限列出目录内容。写权限意味着用户使用该权限能够在目录中创建或者删除文件。执行权限允许用户输入目录并访问任意子目录。没有执行权限,目录下的文件系统对象就是不可访问的。没有读权限,目录下的文件系统对象在目录清单下就是不可见的,但是如果知道磁盘上对象的完整路径,这些对象仍是可访问的。清单 4 是说明这些问题的非常人工的例子。
清单 4. 权限和目录
[ian@echidna ~]$ ls -l /hometotal 32drwxr-x---. 38 editor editor 12288 Nov 30 10:49 editordrwxr-x---. 4 greg development 4096 Nov 30 12:44 gregdrwx------. 21 gretchen gretchen 4096 Nov 30 11:26 gretchendrwxr-xr-x. 41 ian ian 4096 Nov 30 10:51 iandrwx------. 21 ianadmin ianadmin 4096 May 28 2010 ianadmind-wx--x--x. 21 tom tom 4096 Nov 30 11:30 tom[ian@echidna ~]$ ls -a ~greg/.ba*/home/greg/.bash_history /home/greg/.bash_profile/home/greg/.bash_logout /home/greg/.bashrc[ian@echidna ~]$ ls -a ~gretchenls: cannot open directory /home/gretchen: Permission denied[ian@echidna ~]$ ls -a ~tomls: cannot open directory /home/tom: Permission denied[ian@echidna ~]$ head -n 3 ~tom/.bashrc# .bashrc# Source global definitions
长清单的第一个字母表示对象的类型(d
表示目录)。用户 greg 的主目录有 development 组成员的读和写权限,因此用户 tom 和 ian 能够列出目录。用户 gretchen 的主目录没有 gretchen 组或者其他用户的读和执行权限,所以用户 ian 不能访问它。用户 tom 的主目录有执行权限,但是没有读权限,所以用户 ian 不能列出内容,但是如果知道对象存在,就可以访问目录下的对象。
其他文件系统对象
ls -l
的输出可能包含文件系统对象,而不是文件和目录,如清单中第一个字母所示。在后面的文章中我们还会见到更多,但是现在,只是说明可能的对象类型。
表 1. 文件系统对象类型
第 11 个字符
来自 ls
命令中长清单的第 11 个字符是最近才出现的,所以部分版本仍只显示头 10 个字符。在其他情况下,第 11 个字符是一个空格,所以您可能没有注意到。这个字符表示是否有替换的访问方法应用到文件。当跟随文件模式位的字符是空格时,就表示没有替换访问方法。当是一个可打印字符时,就有替换方法。这个方法可能是例子的访问控制清单。GNU ls
使用一个 ‘.’(点)来表示文件只有一个 SELinux 安全上下文。有其他替换访问方法的文件用 ‘+’(加号)表示。
变更权限
添加权限
假设您创建一个 “Hello world” 的 shell 脚本。当您第一次创建脚本时,它通常是不可执行的。使用 chmod
命令和 +x
选项添加执行权限,如清单 5 所示。
清单 5. 创建可执行的 shell 脚本
[ian@echidna ~]$ echo 'echo "Hello world!"'>hello.sh[ian@echidna ~]$ ls -l hello.sh-rw-rw-r--. 1 ian ian 20 Nov 30 13:05 hello.sh[ian@echidna ~]$ ./hello.shbash: ./hello.sh: Permission denied[ian@echidna ~]$ chmod +x hello.sh[ian@echidna ~]$ ./hello.shHello world![ian@echidna ~]$ ls -l hello.sh-rwxrwxr-x. 1 ian ian 20 Nov 30 13:05 hello.sh
您可以按类似的方法使用 +r
来设置读权限,使用 +w
设置写权限。事实上,您可以联合使用 r
、w
和 x
。例如,使用 chmod +rwx
将会设置文件的所有读、写和执行权限。chmod
会添加尚未设置的权限。
可选性
您在上面的例子中可能已经注意到,执行权限被设置给所有者、组 和 其他。为了更具可选性,您可以给模式描述加前缀 u
来设置用户权限,g
来设置组权限,还有 o
为其他人设置。需要指出的是 a
设置所有用户的权限,这就相当于忽略它。清单 6 显示了如何添加用户和组写和执行权限到 shell 脚本的其他副本。
清单 6. 有选择性地添加权限
[ian@echidna ~]$ echo 'echo "Hello world!"'>hello2.sh[ian@echidna ~]$ chmod ug+xw hello2.sh[ian@echidna ~]$ ls -l hello2.sh-rwxrwxr--. 1 ian ian 20 Nov 30 13:08 hello2.sh
删除权限
有时您需要删除权限,而不单单是添加。简单地将 +
改变为 -
,就能删除任何已设置的指定权限。清单 7 显示了如何删除两个 shell 脚本上的其他用户的所有权限。
清单 7. 删除权限
[ian@echidna ~]$ ls -l hello*.sh-rwxrwxr--. 1 ian ian 20 Nov 30 13:08 hello2.sh-rwxrwxr-x. 1 ian ian 20 Nov 30 13:05 hello.sh[ian@echidna ~]$ chmod o-xrw hello*.sh[ian@echidna ~]$ ls -l hello*.sh-rwxrwx---. 1 ian ian 20 Nov 30 13:08 hello2.sh-rwxrwx---. 1 ian ian 20 Nov 30 13:05 hello.sh
请注意,您可以一次改变一个或者多个文件的权限。正如在 topic 103 的文章中看到其他命令一样,您甚至可以使用 -R
(或者 --recursive
)选项在目录和文件上进行递归操作。
设置权限
现在已经可以添加或者删除权限了,您可能会想,怎样才能只设置一些特殊权限。使用 =
替换 +
或者 -
来完成这个动作。要在上述脚本中设置权限,这样其他用户就没有访问权利,您可以使用 chmod o= hello*
替换我们用于删除权限的命令。
如果您想对用户、组合或其他设置不同的权限,您可以通过逗号分隔不同的表达;例如,ug=rwx,o=rx
,或者您可以使用稍后提到的数字权限。
八进制权限
目前为止,您都是使用符号(ugoa 和 rxw)来指定权限。每组中有三个可能的权限。您还可以使用八进制取代符号设置权限。按这种方法设置的权限使用高达 4 位八进制数字。讨论属性时,我们会查看第 1 个数字。第 2 个数字定义了用户权限,第 3 个是组权限,第 4 个是其他权限。这三个数字中的每一个都通过添加所需的权限设置来构建:读(4),写(2)和执行(1)。在 清单 5 中的 hello.sh 例子中,创建的脚本有权限 -rw-r--r--,相当于八进制 644。设置每个人的执行权限将模式改为 755。
当您想要一次设置所有权限,而不给予每个组相同权限时,设置使用数字权限非常方便。使用 表 2 作为一个方便的八进制权限参考。
表 2. 数字权限
rwx
7
rw-
6
r-x
5
r--
4
-wx
3
-w-
2
--x
1
---
0
suid 和 sgid
Linux 权限模型有两个特殊的访问模式,名为 suid(设置用户 id)和 sgid(设置组 id)。当可执行的程序设置为 suid 访问模式,它就会开始运行,好像是由文件所有者启动而不是由真正启动它的用户启动。类似的,设置为 sgid 访问模式,程序就会运行,好像启动用户属于文件组,而不属于他所有的组。可以单独或者同时设置两个访问模式。
清单 8 显示了可执行的 passwd
由 root 所有:
清单 8. /usr/bin/passwd 上的 suid 访问模式
[ian@echidna ~]$ ls -l /usr/bin/passwd-rwsr-xr-x. 1 root root 34368 Apr 6 2010 /usr/bin/passwd
请注意,在用户的权限三件套中 x
的位置上有一个 s
。这就表示,对这个特定的程序来说,suid 和可执行位已经被设置。所以,当 passwd
运行时,它就会像 root 用户使用完全的 superuser 访问一样加载它运行,而不是作为想运行该程序的用户。因为 passwd
和 root
访问一起运行,所以它可以修改 /etc/passwd。
suid 和 sgid 位与长目录清单中用户和组的 x
占据相同的空间。如果文件是可执行的,suid 或 sgid 位如果已设置,将会显示为小写的 s
,否则就显示为大写的 S
。
虽然 suid 和 sgid 很便利,甚至在很多环境下是必需的,但是这些访问模式不适当的使用会造成系统安全上的漏洞。您要尽量少地使用 suid 程序。passwd
命令是少数 必须 为 suid 的命令之一。
设置 suid 和 sgid
suid 和 sgid 位使用字母 s
在符号上进行设置和重设;例如,u+s
设置 suid 访问模式,g-s
删除 sgid 模式。在八进制格式中,suid 在第一位(高阶)为值 4,而 sgid 是值 2。
目录和 sgid
当一个目录使用 sgid 模式时,在这个目录中创建的任何文件和目录将会继承目录的组 id。这个对那些被从事同一项目的一组人使用的目录树极为有用。 清单 9 显示了用户 greg 任何设置一个 development 组所有用户都能使用的目录,以及一个示例,用户 gretchen 如何在目录上创建一个文件。正如所创建的,文件 gretchen.txt 允许组成员编辑文件,因此 gretchen 使用 chmod g-w
来取消组的写功能。
清单 9. sgid 访问模式和目录
[greg@echidna ~]$ mkdir lpi101[greg@echidna ~]$ chmod g+ws lpi101[greg@echidna ~]$ ls -ld lpi101drwxrwsr-x. 2 greg development 4096 Nov 30 13:30 lpi101/[greg@echidna ~]$ su - gretchenPassword: [gretchen@echidna ~]$ touch ~greg/lpi101/gretchen.txt[gretchen@echidna ~]$ ls -l ~greg/lpi101/gretchen.txt-rw-rw-r--. 1 gretchen development 0 Nov 30 14:12 /home/greg/lpi101/gretchen.txt[gretchen@echidna ~]$ chmod g-w ~greg/lpi101/gretchen.txt[gretchen@echidna ~]$ ls -l ~greg/lpi101/gretchen.txt-rw-r--r--. 1 gretchen development 0 Nov 30 14:12 /home/greg/lpi101/gretchen.txt
development 组的任何成员现在都能够在用户 greg 的 lpi101 目录上创建文件了。正如 清单 10 所示,组的其他用户不能升级文件 gretchen.txt。但是,他们有对目录的写权限,因此可以删除文件。
清单 10. sgid 访问模式和文件所有权
[gretchen@echidna ~]$ su - tomPassword: [tom@echidna ~]$ echo "something" >> ~greg/lpi101/gretchen.txt-bash: /home/greg/lpi101/gretchen.txt: Permission denied[tom@echidna ~]$ rm ~greg/lpi101/gretchen.txtrm: remove write-protected regular empty file `/home/greg/lpi101/gretchen.txt'? y[tom@echidna ~]$ ls -l ~greg/lpi101/total 0
粘贴位
您刚看到了任何有目录写权限的人如何删除目录中的文件。这对一个工作组项目是可接受的,但是对全球共享的文件空间,例如 /tmp 目录,是不希望的。幸运的是,有解决方案。
剩下的访问模式为就称为粘贴 位。用符号表示就是 t
,用数字表示就是八进制位的高阶为 1。它显示在其他用户的可执行标识中(最后的字符)的长目录清单,而且 suid 和 sgid 的大小写意义相同。如果设置一个目录,它只允许有所有权的用户或者 superuser(root)删除或者解除文件链接。清单 11 显示了用户 greg 如何在他的 lpi101 目录上设置粘贴位,还显示了这个位设置用于 /tmp。
清单 11. 粘贴目录
[greg@echidna ~]$ chmod +t lpi101[greg@echidna ~]$ ls -ld lpi101 /tmpdrwxrwsr-t. 2 greg development 4096 Nov 30 14:16 lpi101drwxrwxrwt. 24 root root 12288 Nov 30 14:22 /tmp
在以前,UNIX® 系统曾在文件上使用粘贴位在交换空间囤积可执行文件,避免重新加载。现代 Linux 内核忽略了粘贴位,如果它是设置给文件的。
访问模式的总结
表 3 总结了这里讨论的 3 种访问模式的符号和八进制表示。
表 3. 访问模式
s
with u
4000
sgids
with g
2000
stickyt
1000
将这些和早先的权限信息结合在一起,您可以看到对应 greg 的 lpi101 权限和 drwxrwsr-t 访问模式的完整的八进制表示是 3775。虽然 ls
命令不显示八进制权限,您可以使用 find
命令进行显示,如清单 12清单 12 所示。
清单 12. 可打印的符号和八进制权限
[greg@echidna ~]$ find . -name lpi101 -printf "%M %m %f\n"drwxrwsr-t 3775 lpi101
不可变文件
访问模式和权限提供了广泛的控制,限制了谁可以在文件和目录上做什么。但是,它们对有些事情也不能避免,如 root 用户对文件的无心删除。虽然这不在 LPI Topic 104.5 的范围内,但是在提供额外功能的文件系统上还是有些可用的附加属性。其中之一就是不可变 属性。设置完成后,即使是 root 用户也不能删除文件,直到属性解除。
使用 lsattr
命令查看文件或者目录是否设置了不可变标识(或者任何其他属性)。要将一个文件设置为不可变,使用 chattr
命令和 -i
标识。
清单 13清单 13 显示了用户 root 可以创建一个不可变文件,但是不能删除它,直到不可变标识被删除。
清单 13. 不可变文件
[root@echidna ~]# touch keep.me[root@echidna ~]# chattr +i keep.me[root@echidna ~]# lsattr keep.me----i--------e- keep.me[root@echidna ~]# rm -f keep.merm: cannot remove `keep.me': Operation not permitted[root@echidna ~]# chattr -i keep.me[root@echidna ~]# rm -f keep.me
变更不可变标识需要 root 授权,或者最少 CAP_LINUX_IMMUTABLE 功能。使文件不可变通常是安全或者入侵检测工作的一部分。见功能使用页面(man capabilities
)了解更多信息。
文件创建屏蔽
创建一个新文件时,创建进程就会指明新文件的权限。通常,所需的模式是 0666,它使文件可由任何人读和写。目录默认为 0777。但是,这个宽松的创建会受到 umask 值的影响,这个值指明了用户不想自动授予新创建的文件或者目录什么权限。系统使用 umask 值来减少原始请求的权限。您可以使用 umask
查看 umask 设置,如清单 14清单 14 所示。
清单 14. 显示八进制 umask
[ian@echidna ~]$ umask0002
请记得,umask 指定了那个权限不被授予。在 Linux 系统上,用户没有专用组的的情况下,umask 通常默认为 0022,它可以从新文件中删除组和其他写权限。用户有专用组的情况下(例如这些例子中使用的在 Fedora 系统上),umask 通常默认为 0002,它删除了其他用户的写权限。使用 -S
选项来从符号上显示 umask,以显示哪个权限被允许的形式。
使用 umask
命令设置一个 unmask 并显示。所以,如果您想要保持文件更专有,并且不允许所有组或者其他人访问新创建的文件,就是可以使用 umask 值 0077。或者从符号上,使用 umask u=rwx,g=,o=
进行设置,如清单 15清单 14 所示。
清单 15. 设置 umask
[ian@echidna ~]$ umask -Su=rwx,g=rwx,o=rx[ian@echidna ~]$ umask u=rwx,g=,o=[ian@echidna ~]$ umask0077[ian@echidna ~]$ touch newfile[ian@echidna ~]$ ls -l newfile-rw-------. 1 ian ian 0 Nov 30 15:40 newfile
设置文件所有者和组
文件组
要变更文件的组,使用 chgrp
命令和组名,以及一个或者多个文件名。如果您喜欢,还可以使用组编号。普通用户必须拥有文件,同时是文件要变更到的组的组员。root 用户可以将文件变更到任意组。清单 16清单 16 显示了一个例子。
清单 16. 变更组的所有权
[ian@echidna ~]$ touch file{1,2}[ian@echidna ~]$ ls -l file*-rw-rw-r--. 1 ian ian 0 Nov 30 15:54 file1-rw-rw-r--. 1 ian ian 0 Nov 30 15:54 file2[ian@echidna ~]$ chgrp development file1[ian@echidna ~]$ chgrp 505 file2[ian@echidna ~]$ ls -l file*-rw-rw-r--. 1 ian development 0 Nov 30 15:54 file1-rw-rw-r--. 1 ian development 0 Nov 30 15:54 file2
正如该教程中的许多其他命令,chgrp
有一个 -R
选项,允许将变更递归应用到所有所选的的文件和子目录中。
默认组
当您学习之前的 访问模式 时,您就了解了在目录上设置 sgid 模式如何导致创建在该目录下的新文件属于目录的组,而不是属于创建该文件的用户所在的组。
您还可以使用 newgrp
命令来暂时地将您的初级组变更到您所在的其他组。创建一个新的 shell,当您退出 shell 时,之前的组就能恢复,如清单 17清单 17 所示。
清单 17. 使用 newgrp 来暂时改变默认组
[ian@echidna ~]$ groupsian development editor[ian@echidna ~]$ newgrp development[ian@echidna ~]$ groupsdevelopment ian editor[ian@echidna ~]$ touch file3[ian@echidna ~]$ ls -l file3-rw-r--r--. 1 ian development 0 Nov 30 16:00 file3[ian@echidna ~]$ exit[ian@echidna ~]$ groupsian development editor
文件所有者
root 用户可以使用 chown
命令变更文件的所有权。在它最简单的形式中,语法和 chgrp
命令类似,除了使用用户名或者数字 id,而不是组名或者 id。文件的组也可能通过在用户名或者 id 之后添加一个冒号和组名或者 id 来同时变更。如果只有给出冒号,那么就使用用户的默认组。一般来说,-R
选项会递归地应用变更。清单 18清单 18 给出了一个例子。
清单 18. 使用 chown 变更文件所有权
[ian@echidna ~]$ touch file4[ian@echidna ~]$ su -Password: [root@echidna ~]# ls -l ~ian/file4-rw-rw-r--. 1 ian ian 0 Nov 30 16:04 /home/ian/file4[root@echidna ~]# chown greg ~ian/file4[root@echidna ~]# ls -l ~ian/file4-rw-rw-r--. 1 greg ian 0 Nov 30 16:04 /home/ian/file4[root@echidna ~]# chown tom:gretchen ~ian/file4[root@echidna ~]# ls -l ~ian/file4-rw-rw-r--. 1 tom gretchen 0 Nov 30 16:04 /home/ian/file4[root@echidna ~]# chown :tom ~ian/file4[root@echidna ~]# ls -l ~ian/file4-rw-rw-r--. 1 tom tom 0 Nov 30 16:04 /home/ian/file4
指定用户和组的较早版本使用点,而不是冒号。因为当名称中包含点时,这个可能会造成误解,所以已经不再推荐。
Linux 上的文件和目录权限介绍就到此为止。
- Linux-管理文件权限和所有权
- 管理Linux文件权限和所有权
- 管理文件权限和所有权
- 学习 Linux,101: 管理文件权限和所有权
- 修改LINUX目录或文件的权限和所有权详解
- 修改LINUX目录或文件的权限和所有权详解
- 修改LINUX目录或文件的权限和所有权
- 修改LINUX目录或文件的权限和所有权详解
- Linux操作系统的权限和所有权模型
- Linux的权限和所有权模型
- Linux的权限和所有权模型
- Linux的权限和所有权模型(粘滞位)
- Linux的权限和所有权模型(粘滞位)
- Linux的权限和所有权模型
- 对话 UNIX,第 4 部分: UNIX 所有权和权限管理
- linux文件权限管理
- Linux文件权限管理
- Linux文件权限管理
- 数据挖掘10大算法(6)-K最近邻(KNN)算法的实现(java和python版)
- 将svn服务注册成windows服务
- 安卓LISTVIEW
- PowerDesigner 模型导出图片不清晰的问题
- tomcate 端口号占用,Windows的解决方法
- Linux-管理文件权限和所有权
- GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流
- 进制转换
- Tomcat6 配置多虚拟主机,多域名绑定一IP
- android开发环境安装与配置
- mybatis 联合查询
- Ext实现waiting提示功能
- 一张帖搞定同学们入学黑马前所有难题
- PNG文件格式详解