(47)LINUX应用编程和网络编程之二Linux文件属性

 

Linux下的文件系统为树形结构,入口为/ 树形结构下的文件目录: 无论哪个版本的Linux系统,都有这些目录,这些目录应该是标准的。各个Linux发行版本会存在一些小小的差异,但总体来说,还是大体差不多。 1. / 文件系统的入口,最高一级目录; 2. /bin 基础系统所需要的命令位于此目录,是最小系统所需要的命令,如:ls, cp, mkdir等。这个目录中的文件都是可执行的,一般的用户都可以使用。 3. /boot 包含Linux内核及系统引导程序所需要的文件,比如 vmlinuz initrd.img 文件都位于这个目录中。在一般情况下,GRUB或LILO系统引导管理器也位于这个目录; 4. /dev 设备文件存储目录,比如声卡、磁盘... ... 这是一个非常有趣的目录,是Linux文件系统的一个闪亮的特性 - 所有对象都是文件或目录。仔细观察这个目录你会发现hda1, hda2等, 它们代表系统主硬盘的不同分区。/dev/cdrom和/dev/fd0代表你的CDROM驱动器和floppy驱动器。看上去可能有些奇怪,但比较文件和硬件的特性这却是十分合理的。它们都可以读出和写入。例如/dev/dsp,这个文件代表你的扬声器。那么写入这个文件的数据都回传送到喇叭。试一试 'cat /etc/lilo.conf > /dev/dsp' 你会听到一些声音。这是你的 lilo.conf 文件的声音!同样,向 /dev/ttyS0 ( COM 1 ) 读出或写入数据你可以和接到上面的设备进行通讯。 5. /etc 存放系统程序或者一般工具的配置文件。如安装了apache2之后,配置文件在/etc/apache2/目录下。/etc/init.d 这个目录是用来存放系统或服务器以System V模式启动的脚本,这在以System V模式启动或初始化的系统中常见。如apache2的/etc/init.d apache2 start|stop|restart MySQL为/etc/init.d mysql start|stop|restart 6. /home 普通用户默认存放目录 Linux 是多用户环境,所以每一个用户都有一个只有自己可以访问的目录(当然管理员也可以访问)。它们以 /home/username 的方式存在。这个目录也保存一些应用对于这个用户的配置,比如 IRC, X 等。 7. /lib 库文件存放目录这里包含了系统程序所需要的所有共享库文件,类似于 Windows 的共享库 DLL 文件。 8. /lost+found 在ext2或ext3文件系统中,当系统意外崩溃或机器意外关机,而产生一些文件碎片放在这里。当系统启动的过程中fsck工具会检查这里,并修复已经损坏的文件系统。 有时系统发生问题,有很多的文件被移到这个目录中,可能会用手工的方式来修复,或移到文件到原来的位置上。Linux 应该正确的关机。但有时你的系统也可能崩溃掉或突然断电使系统意外关机。那么启动的时候 fsck 将会进行长时间的文件系统检查。Fsck 会检测并试图恢复所发现的不正确的文件。被恢复的文件会放置在这个目录中。所恢复的文件也许并不完整或并不合理,但毕竟提供了一些恢复数据的机会。 9. /media 即插即用型存储设备的挂载点自动在这个目录下创建,比如USB盘系统自动挂载后,会在这个目录下产生一个目录 ;CDROM/DVD自动挂载后,也会在这个目录中创建一个目录,类似cdrom 的目录。这个只有在最新的发行套件上才有. 10. /mnt /mnt 这个目录一般是用于存放挂载储存设备的挂载目录的,比如有cdrom 等目录。有时我们可以把让系统开机自动挂载文件系统,把挂载点放在这里也是可以的。比如光驱可以挂载到/mnt/cdrom 。 这是一个普通的加载目录,在这里你可以加载你的文件系统或设备。加载是使一个文件系统对于系统可用的过程。在加载后你的文件可以在加载目录下访问。这个目录通常包含加载目录或用于加载软驱和光驱的子目录。如果需要,你也可以在这里建立其它的加载目录。对于加载目录的位置并没有强制性的要求,你可以在系统的任意位置建立加载目录。建立 /mnt 只是为了使系统更工整的惯例。 11. /opt 表示的是可选择的意思,有些软件包也会被安装在这里,也就是自定义软件包,比如在Fedora Core 5.0中,OpenOffice就是安装在这里。有些我们自己编译的软件包,就可以安装在这个目录中;通过源码包安装的软件,可以通过 ./configure --prefix=/opt/,将软件安装到opt目录。 这个目录包含所有默认系统安装之外的软件和添加的包。 12. /proc 操作系统运行时,进程(正在运行中的程序)信息及内核信息(比如cpu、硬盘分区、内存信息等)存放在这里。/proc目录是伪装的文件系统proc的挂载目录,proc并不是真正的文件系统。这是系统中极为特殊的一个目录,实际上任何分区上都不存在这个目录。它实际是个实时的、驻留在内存中的文件系统。 13. /root Linux超级权限用户root的家目录; 14. /sbin 大多是涉及系统管理的命令的存放,是超级权限用户root的可执行命令存放地,普通用户无权限执行这个目录下的命令;这个目录和/usr/sbin; /usr/X11R6/sbin或/usr/local/sbin 目录是相似的; 我们记住就行了,凡是目录sbin中包含的都是root权限才能执行的。 15. /tmp 临时文件目录,有时用户运行程序的时候,会产生临时文件。 /tmp就用来存放临时文件的。/var/tmp目录和这个目录相似。许多程序在这里建立lock文件和存储临时数据。有些系统会在启动或关机时清空此目录。 16. /usr 这个是系统存放程序的目录,比如命令、帮助文件等。这个目录下有很多的文件和目录。当我们安装一个Linux发行版官方提供的软件包时,大多安装在这里。如果有涉及服务器配置文件的,会把配置文件安装在/etc目录中。 /usr目录下包括:涉及字体目录/usr/share/fonts ,帮助目录 /usr/share/man或/usr/share/doc,普通用户可执行文件目录/usr/bin 或/usr/local/bin 或/usr/X11R6/bin ,超级权限用户root的可执行命令存放目录,比如 /usr/sbin 或/usr/X11R6/sbin 或/usr/local/sbin 等;还有程序的头文件存放目录/usr/include。 /usr/bin 这个目录是可执行程序的目录,普通用户就有权限执行; 当我们从系统自带的软件包安装一个程序时,他的可执行文件大多会放在这个目录。/usr/sbin 这个目录也是可执行程序的目录,但大多存放涉及系统管理的命令。只有root权限才能执行;相似目录是/sbin 或/usr/local/sbin或/usr/X11R6/sbin等; /usr/local 这个目录一般是用来存放用户自编译安装软件的存放目录;一般是通过源码包安装的软件,如果没有特别指定安装目录的话,一般是安装在这个目录中。这个目录下面有子目录。/usr/lib 和/lib 目录相似,是库文件的存储目录;/usr/share 系统共用的东西存放地,比如 /usr/share/fonts 是字体目录,是用户都共用的吧。/usr/share/doc和/usr/share/man帮助文件,也是共用的吧; /usr/src 是内核源码存放的目录,比如下面有内核源码目录,比如 linux 、linux-2.xxx.xx 目录等。有的系统也会把源码软件包安装在这里。比如Fedora/Redhat,当我们安装file.src.rpm的时候,这些软件包会安装在 /usr/src/redhat相应的目录中。请参考: 《file.src.rpm 使用方法的简单介绍》 。另外Fedhat 4.0 5.0,他的内核源码包的目录位于/usr/src/kernels目录下的某个目录中(只有安装后才会生成相应目录); 17. /var 这个目录的内容是经常变动的,看名字就知道,我们可以理解为vary的缩写,/var下有/var/log 这是用来存放系统日志的目录。/var/www目录是定义Apache服务器站点存放目录;/var/lib 用来存放一些库文件,比如MySQL的,以及MySQL数据库的的存放地;/var/log 系统日志存放,分析日志要看这个目录的东西;/var/spool 打印机、邮件、代理服务器等假脱机目录; Windows和Linux文件系统的区别 Linux文件系统与Windows文件系统有很大的差别。Linux文件系统作为开端,只有一个单独的顶级目录结构。所有一切都从 '根' 开始,用 '/' 代表, 并且延伸到子目录。DOS/Windows有不同的分区,同时目录都存于分区上。linux则通过 '加载' 的方式把所有分区都放置在 '根' 下制定的目录里。一句话总结:Windows下,目录结构属于分区;Linux下,分区 '加载' 于目录结构。 在Windows下, 启动时检测不同的分区并被赋予一个分区字母。在Linux下除非你加载一个分区或设备,否则系统不会知道那个分区的存在。这看上去也许不是访问分区或设备的最方便的方式,但是这种方式提供了伟大的机动性。这种构建的方式被称为统一的文件系统,超越了Windows所使用的方式。举个使用 /usr 的例子。这个目录包含了大多数的系统可执行文件。在Linux文件系统下,你可以选择把它加载为其他分区甚至网络上的其他计算机。系统不会感知其中的不同,因为它表现出的只是本地目录结构下众多的目录中的一个而已。你是否有妄图在Windows下移动可执行文件和数据,而得到的是不得不去修改注册表或干脆蓝屏?你可曾奢望过移动 C: 到其他分区上?
存储设备进行格式化(即建立文件系统)

1。关于文件系统

对存储设备分区还是不够的,我们还要对新增分区进行格式化;一个分区只有建立了某种文件系统后,这个分区才能使用;建立文件系统过程,就是用相应格式化工具格式化分区的过程,这个过程和我们在Windows中格式化某个分区为NTFS分区类似;没有什么高深的内容,只是所用的工具不一样罢了;

Linux操作系统中,几乎支持目前主流的文件系统,比如NTFS(只读)、FAT(可读可写)、ext2、ext3、reiserfs、hfs (MAC 操作系统的文件系统)、swap 交换分区... ... 还有一些咱们不熟悉的操作系统的文件系统等;

在Linux中,我们常用的文件系统无非是上面例出的这些;如果您新增了一个硬盘,可能想格 式化成 Linux的文件系统,最佳选择是 reiserfs 或ext3;目前ext2已被 ext3取代;我们不推荐用ext2文件系统,ext2的使用风险比较大;速度最快的文件系统,当属reiserfs;reiserfs 还有很多优点,比如更安全;ext3是Redhat认为最好的文件系统。

相对来说reiserfs还是比ext3要优秀。

 

 

 

文件系统概念

1。*nix系统中:一切皆文件;

2。文件

a. )文件的成分: 无论文件是一个程序、一个文档、一个数据库,或者是一个目录,操作系统都会赋予它如下所示的同样的结构:
◆索引节点又称I节点,在文件系统结构中,包含有关相应文件的信息的一个记录,这些信息包括文件权限、文件主、文件大小、存放位置、建立日期等。
◆数据文件的实际内容,它可以是空的,也可以非常大,并且有自己的结构。

b.) Linux系统区分文件名的大小写

以圆点“.”开头的文件名是隐含文件(dot files),默认方式下使用ls命令并不能把它们在屏幕上显示出来。同样,在默认情况下,Shell通配符并不匹配这类文件名。

c.) 文件名通配符

星号(*): 与0个或多个任意的字符相匹配

问号(?): 问号只与一个任意的字符匹配,可以使用多个问号

方括号([ ]) : 与问号相似,只与一个字符匹配。它们的区别在于,问号与任意一个字符匹配,而方括号只与括号中列出的字符之一匹配。例如letter [123]只与文件letter1、letter2或letter3匹配,但不与文件 letter12匹配。可以用短横线代表一个范围内的字符,而不用将它们一一列出。例如,letter[1-3]是letter[123]的简写形式。但是,要注意范围内的字符都按升序排列,即[A-Z]是有效的,而[Z-A]是无效的。方括号中可以列出多个范围,如[A-Za-z]可以和任意大写或小写 的字符相匹配。方括号中如果以惊叹号“!”开始,表示不与惊叹号后的字符匹配。

 


文件类型

Linux操作系统支持普通文件、目录文件、特别文件及符号链接文件等文件类型。

 


1. 普通文件

普通文件也称作常规文件,包含各种长度的字节串。核心对这些数据没有进行结构化,只是作为有序的字节序列把它提交给应用程序。应用程序自己组织和解释这些数据,通常把它们归并为下述类型之一:
◆文本文件,由ASCII字符构成。例如,信件、报告和称作脚本(Script)的命令文本文件,后者由shell解释执行。
◆数据文件,由来自应用程序的数字型和文本型数据构成。例如,电子表格、数据库,以及字处理文档。
◆可执行的二进制程序,由机器指令和数据构成。例如,上面所说的系统提供的命令。

使用file命令可以确定指定文件的类型。该命令可以将任意多个文件名当做参数,其一般使用格式是:file 文件名 [文件名...]

2. 目录

目录是一类特殊的文件,利用它可以构成文件系统的分层树型结构。如同普通文件那样,目录文件也包含数据;但目录文件与普通文件的差别是,核心对这些数据加以结构化,它是由成对的“I节点号/文件名”构成的列表。
◆I节点号是检索I节点表的下标,I节点中存放有文件的状态信息。
◆文件名是给一个文件分配的文本形式的字符串,用来标识该文件。在一个指定的目录中,任何两项都不能有同样的名字。

每个目录的第一项都表示目录本身,并以“.”作为它的文件名。每个目录的第二项的名字是“..”,表示该目录的父目录。

应注意:以“.”开头的文件名表示隐含文件,使用带-a选项的ls命令可以列出它们。

当把文件添加到一个目录中的时候,该目录的大小会增长,以便容纳新文件名。当删除文件时,目录的尺寸并不减少,而是核心对该目录项做上特殊标记,以便下次添加一个文件时重新使用它。ls命令不会列出这些未被使用的项。

Linux系统的目录结构

Linux文件系统采用带链接的树形目录结构,即只有一个根目录(通常用“/”表示),其中含有下级子目录或文件的信息;子目录中又可含有更下级的子目录或者文件的信息。这样一层一层地延伸下去,构成一棵倒置的树,如图1所示。


图1 Linux树型目录结构

在目录树中,根节点和中间节点(用圆圈表示)都必须是目录,而普通文件和特别文件只能作为“叶子”出现。当然,目录也可以作为叶子。

(1)用户主目录
当注册进入系统时,主目录就是当前工作目录。主目录往往位于/home目录之下,并且与注册名相同,例如,/home/mengqc。通常主目录包含子目录、数据文件,以及用于注册环境的配置文件。

绝对路径和相对路径

什么情况下使用绝对路径名,什么情况下使用相对路径名,取决于哪种方式涉及到的目录更少。路径短,不仅键盘输入少,而且节省系统搜索路径的时间,提高执行效率。例如,当前的工作目录是 /etc/conf/cf.d,如果需要访问系统口令文件/etc/passwd,那么使用绝对路径名是/etc/passwd,使用相对路径名是.. /../passwd。绝对路径名/etc/passwd涉及的目录有2个,而相对路径名../../passwd涉及的目录却是3个。此时,使用绝对路 径名更有效。

但是,如果当前工作目录是/home/mengqc/lib,要访问在 func目录之下的file1文件,那么使用绝对路径名是/home/mengqc/lib/func/file1,使用相对路径名是 func/file1。绝对路径名/home/mengqc/lib/func/file1涉及的目录有5个,而相对路径名涉及的目录只有2个。此时,使用相对路径名更有效。

如果不清楚当前工作目录与其它目录之间的关系,那么最好使用绝对路径名。

 


3. 设备文件
在Linux系统中,所有设备都作为一类特别文件对待,用户像使用普通文件那样对设备进行操作,从而实现设备无关性。但是,设备文件除了存放在文件I节点中的信息外,它们不包含任何数据。系统利用它们来标识各个设备驱动器,核心使用它们与硬件设备通信。

有两类特别设备文件,它们对应不同类型的设备驱动器:
◆字符设备 最常用的设备类型,允许I/O传送任意大小的数据,取决于设备本身的容量。使用这种接口的设备包括终端、打印机及鼠标。
◆块设备 这类设备利用核心缓冲区的自动缓存机制,缓冲区进行I/O传送总是以1KB为单位。使用这种接口的设备包括硬盘、软盘和RAM盘。

 

 

 

Linux系统的文件系统路径
1。路径分为绝对路径和相对路径。

绝对路径是从/(也被称为根目录)开始的,比如/usr、/etc/X11。如果一个路径是从/开始的,它一定是绝对路径。

相对路径是以 . 或 .. 开始的,.表示用户当前操作所处的位置,而.. 表示上级目录;在路径中,.表示用户当前所处的目录,而..上级目录,要把.和..当做目录来看。

2。[root@localhost ~]# pwd 注:判断用户当前所处的位置,也就是说他到底位于哪?

use when you are lost.

3。

[root@localhost ~]# cd . 注:我们进入。

[root@localhost ~]# cd .. 注:我们切入/root的上级目录。

注意,cd之后有个空格。

 


4。~ 表示当前用户自己的家目录;

~USER 表示用户名为USER的家目录

如:

cd ~ 回到当前用户的家目录;

cd ~USERNAME 回到USERNAME用户的家目录;

 

 

 

 


文件系统及其安装

一个硬盘上可以同时存在多个文件系统,每个文件系统占据硬盘的一个独立分区。Linux文件系统可以根据需要随时装卸,从而实现文件存储空间的动态扩充和信息安全。在系统初启时,往往只有一个文件系统被安装上,即根文件系统,其上的文件主要是保证系统正常运行的操作系统的代码文件,以及若干语言编译程序、命令解释程序和相应的命令处理程序等构成的文件,此外,还有大量的用户文件空间。根文件系统一旦安装上,则在整个系统运行过程中是不能卸下的,它是系统的基本部分。

其它的文件系统(例如,由软盘构成的文件系统)可以根据需要(如从硬盘向软盘复制文件),作为子系统动态地安装到主系统中,如图5所示。其中,mnt是为安装子文件系统而特设的安装节点。


图5 文件系统安装

经过安装之后,主文件系统与子文件系统就构成一个有完整目录层次结构的、容量更大的文件系统。这种安装可以高达几级。就是说,若干子文件系统可以并列安装到主文件系统上,也可以一个接一个地串连安装到主文件系统上。

已安装的子文件系统也可从整个文件系统上卸下来,恢复安装前的独立状态。

1.建立文件系统
当硬盘完成分区后,应该在该分区上建立文件系统。这一步工作是通过mkfs工具来完成的。例如,如果需要在分区/dev/hda1上建立ext2文件系统,并检查坏块,应该使用以下命令:
# mkfs -c /dev/hda1

注意,只有root用户才能建立或安装/卸下文件系统。

2.安装文件系统
创建文件系统后,需要使用命令mount将该文件系统安装到主文件系统中。命令mount有三个主要参数:
◆需要安装的文件系统类型,用“-t fstype”选项来指定,这与mkfs中的-t选项是一样的。
◆所需访问的文件系统所在分区名,通常是位于目录/dev中的特别设备文件;如果需要安装网络文件系统时,就使用该服务器上输出的目录名。
◆ 安装新文件系统的路径名,也就是放置新文件系统的安装点(Mount Point)。通常这是一个空目录名,并且是专门为安装新文件系统而准备的。在Linux系统下,目录/mnt是常用的文件系统安装目录,缺省情况下, CDROM和软盘驱动器都分别安装在其子目录下。当然,文件系统也可以被安装到其它空目录中。例如,需要将MSDOS文件系统分区/dev/hda1安装 到系统的空目录/dos中,应该使用以下命令:
# mount -t msdos /dev/hda1 /dos

3.卸载文件系统
在关闭系统之前,为了保证文件系统的完整性,所有安装的文件系统都必须被卸载。通常在/etc/fstab文件中定义的文件系统都能够自动卸载。但是,对于手工mount的文件系统,在关闭系统之前必须手工卸载。有时候也需要在系统工作过程中手工卸载某个文件系统。手工卸载文件系统必须使用umount命令,umount命令将分区名或分区的安装点作为参数,格式如下:

umount <</font>分区名或分区的安装点>

例如,需要将已经安装到/mnt/floppy目录下的软盘卸载,可以使用以下命令:
# umount /mnt/floppy

要注意,对于正在使用的文件系统,不能使用umount命令卸载。

本讲我们介绍了有关Linux系统中常用命令格式、文件和目录的概念、文件类型、目录结构、文件的存取权限、文件系统的概念及其安装命令等。有关文件操作的命令很多,读者可以通过上机学习各种命令的使用方法,掌握其基本功能。(T111)

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

文件权限一般可认为是0 123 456 789,一共十位:
0:表示该文件的文件类型。Windows里面是使用了一种文件关联的技术,通过扩展名来关联相应的应用程序,使得双击某个文件,就能达到调用相应的应用程序来打开它的目的,这样简单快捷。然而对于用户来说,好处是方便,坏处是隐藏了一个实质性的东西:文件的真正的类型,与其扩展名实际上是毫无关联的。
举例来说:一个纯粹的文本文件,我可以给它命名“我的歌声里.mp3”,然后在win下双击,会调用相应的音乐播放器来打开,结果显而易见,肯定是错误的。那反过来,一个真正的MP3文件我也可以给它命名“花名册.txt”,在win下双击,一般会调用相应的文本编辑器来打开,不过我说你也知道,显示的一定是乱码。
上面两个例子是为了说明一个观点,某个文件真正的类型与其扩展名没一毛钱关系。
那么在不知道文件扩展名的情况下,如何知道文件的类型呢?在Linux是这样的。
Linux中文件类型只有以下这几种:
1.-,普通文件。
2.d,目录文件,d是directory的简写。
3.l,软连接文件,亦称符号链接文件,s是soft或者symbolic的简写。
4.b,块文件,是设备文件的一种(还有另一种),b是block的简写。
5.c,字符文件,也是设备文件的一种(这就是第二种),c是character的文件。
Linux系统最原始的也只有这五种,所以第0位,只能是以上五者之一。
那么你会有疑问,
1.MP3文件是是哪种?答案:普通文件。
2.二进制文件是哪种?答案:普通文件。
3.文本文件是哪种?答案:普通文件。
4.为什么硬连接没有类型表示?答案:硬连接和软连接,名字上虽然只差一个字,本质完全不同,硬连接也是文件。其类型是普通文件。


为什么上面要说这么多呢?目的是为下文做知识铺垫。


那么 123-456-789 都好说,了解这块儿的人都知道,他们只是 【用户-属组-其他 】这三组之间的区别,我们拿其中任意一组作为例子来讲解rwx皆可。
r:read,w:write,x:execute。

 


我们应该如何去记忆这两者之间的区别呢??难道死记硬背?NO。
我们应该知其然还得知其所以然,下面我试图从这查询文件以及内容的本质出发,来阐述rwx权限在这两者身上为何有不同的意义!


理解下面的所说的,需要关于Linux的文件系统的知识做铺垫。如果不知道inode这个概念,基本上就会很吃亏了。


再次强调,文件的内容和该文件当时所用的文件名毫无关联;该文件的类型,也与该文件当时的文件名,毫无关系。


查看一个文件的内容,实际上是这样的一个过程:


举例来说,你用了这个命令:cat /tmp/abc.txt


1.你只传递了一个绝对路径,/tmp/abc.txt,系统首先要知道/tmp/abc.txt文件的inode是多少才行,如何得知呢?
2.记住一个规律,某文件的父目录会(记录)知道该文件的inode号!(此刻我想你是不是悟出一点什么了,不用急,接着往下看)
3.那么我得到“/tmp/abc.txt”这个文件名,我得先知道/tmp目录的情况,要知道/tmp目录的情况,我得先知道/目录的情况,所以我就可以从/目录开始(假设/目录的inode号是0,并且这是【写死的】),然后再去一张叫做inode-table的表中查找inode号0所指向的数据域,然后从数据域里面可以找到一些类似于下面的内容:(看起来像一张表,不是么?其实可以想象到,目录文件就是一张表,存储了它内部有哪些【文件名】,以及该文件名对应的inode号)
文件名 inode号
bin 18
var 19
tmp 20
... ...
好了,我们从“/”,这个目录文件中找到了“/tmp”【文件名】对应的inode号,就是20。(假设啊)
4.然后我们通过inode号20,去inode-table里面找寻20对应的数据域,然后从数据域中,我们又会找到一张表:(为什么又是表呢?因为“/”是一个目录,“/tmp”也是一个目录,那当然数据域里面存的还是表啦)
文件名 inode号
abc.txt 8899
bbb.mp3 10088
kkk.jpg 20000
... ...
好了,我们找到了/tmp/abc.txt的inode号了,就是8899。根据上面的规律,我们是不是又得去inode-table里面找8899号对应的数据域了?对,就是这样。
5.我们找到inode号8899对应的数据域,于是我们会发现如下一些内容:
“abcdefg”(假设文件内容就是这样)
...


又有疑问了,为毛这次不是表了?
答案:/tmp/abc.txt文件【不是目录文件】了,它【是一个普通文件,他存储的一般都是一些字符串】。

 


体现在本质上:
普通文件:存储普通数据,一般就是字符串。
目录文件:存储了一张表,该表就是该目录文件下,所有文件名和inode的映射关系。
从父目录中获得本文件的inode号---->找到inode-table表中找到这个inode号对应的数据域中的起点以及其他信息---->去这个数据域中读取该文件的内容(普通文件的内容一般是字符串,目录文件的内容是一张表)
如果你真心看懂上面我说的了,那么接下来就变得简单多了。


关键就是访问任何一个文件,要看是否能搞到inode号,搞不到就没辙了。搞到inode就好说了,拿着inode号去inode表中查找即可,最后找到数据域,那么就可以找到文件的内容了
然后整个过程这不仅仅跟本文件权限有关,还跟它的父目录(还有父目录的父目录...)权限有关(是否能搞到本文件的inode)


体现在命令上:(话说这才是最实际的表象)
======
对于普通文件来说,rwx的意义是:
r:可以获得这个普通文件的名字和内容。
w:可以修改这个文件的内容和文件名。可以删除该文件,但是用户会得到是否删除写保护文件的prompt。
x:该文件是否具有被执行的权限。
======
对于目录文件来说,rwx的意义是:
r-x:可以进入cd该目录,可以获得该目录下存储情况,但是不能修改这个目录内部存储的文件(目录)的名字,也不能在该目录下新建文件和目录
-wx:可以进入cd该目录,但是看不到该目录下的存储情况(ls不可用),可以往该目录下添加、修改、删除文件。可以通过cat来读取该目录下的文件or目录的内容,由于得不到该目录下存储了那些文件,在不知情的情况下只能通过猜,cat + 【文件名】获得文件内容,所以这样依然不保密。
--x:可以进入cd该目录,看不到存储情况,也不能往该目录下添加、修改、删除文件。但是依然可以通过cat + xx(猜)来获得该目录下的文件的内容。
rw-:不能进入cd该目录,用ls仅仅可以获得文件名和目录名,因为获取不到这些文件的inode号,当然也不能获得该目录下的文件的内容。不能往该目录下添加、修改、删除文件。
======

 

最后总结一下吧:
1.目录文件虽然是文件(唉,谁叫Linux的核心理念就是Everything is file),但是存储内容的只是一张表而已,关于文件名和inode号的映射关系。
2.文件的扩展名和文件类型之间,没一毛钱关系。
3.文件的文件名和文件实际存储内容之间,没一毛钱关系,只是作为用户的一种识别标记。
4.要知道如何查找到一个文件内容的过程。
5.为什么同一个文件系统移动文件要比跨文件系统快?
答:因为只需要修改某个目录中路径和inode对应关系即可,不需要重新写一遍数据域。
6.什么是买来的500G的硬盘,格式化完后总是少了达不到500G?
答:从本文可知,inode-table也是需要占用存储空间的,所以缺少的一部分中inode-table占用了不少。
7.我不想吃亏,那么我要如何了解Linux文件系统和inode的相关知识,能否推荐个文章?
答:http://www.cyberciti.biz/tips/understanding-unixlinux-filesystem-inodes.html

 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.2.1.1、普通文件(-    regular file)
(1)文本文件。文件中的内容是由文本构成的,文本指的是ASCII码字符。文件里的内容本质上都是数字(不管什么文件内容本质上都是数字,因为计算机中本身就只有1和0),而文本文件中的数字本身应该被理解为这个数字对应的ASCII码。常见的.c文件, .h文件  .txt文件等都是文本文件。文本文件的好处就是可以被人轻松读懂和编写。所以说文本文件天生就是为人类发明的。
(2)二进制文件。二进制文件中存储的本质上也是数字,只不过这些数字并不是文字的编码数字,而是就是真正的数字。常见的可执行程序文件(gcc编译生成的a.out,arm-linux-gcc编译连接生成的.bin)都是二进制文件。
(3)对比:从本质上来看(就是刨除文件属性和内容的理解)文本文件和二进制文件并没有任何区别。都是一个文件里面存放了数字。区别是理解方式不同,如果把这些数字就当作数字处理则就是二进制文件,如果把这些数字按照某种编码格式去解码成文本字符,则就是文本文件。
(4)我们如何知道一个文件是普通文本文件还是二进制文件?在linux系统层面是不区分这两个的(譬如之前学过的open、read、write等方法操作文件文件和二进制文件时一点区别都没有),所以我们无法从文件本身准确知道文件属于哪种,我们只能本来就知道这个文件的类型然后用这种类型的用法去用他。有时候会用一些【后缀名】来人为的标记文件的类型。
(5)使用文本文件时,常规用法就是用文本文件编辑器去打开它、编辑它。常见的文本文件编辑器如vim、gedit、notepad++、SourceInsight等,我们用这些文本文件编辑器去打开文件的时候,编辑器会read读出文件二进制数字内容,然后按照编码格式去解码将其还原成文字展现给我们。如果用文本文件编辑器去打开一个二进制文件会如何?这时候编辑器就以为这个二进制文件还是文本文件然后试图去将其解码成文字,但是解码过程很多数字并不对应有意义的文字所以成了乱码。
(6)反过来用二进制阅读工具去读取文本文件会怎么样?得出的就是文本文字所对应的二进制的编码。
 
3.2.1.2、目录文件(d    directory)就是目录里的文件。
(1)目录就是文件夹,文件夹在linux中也是一种文件,不过是特殊文件。用ls打开一个文件夹就能看到,文件夹其实也是一种特殊文件,里面存的内容包括这个文件的路径,还有文件夹里面的文件列表。
(2)但是文件夹这种文件比较特殊,本身并不适合用普通的方式来读写。linux中是使用特殊的一些API来专门【读写文件夹】的。
(3)目录文件和文件目录有什么区别?
比如你有1 2 3三个图片文件存放在E:psd里。
“1”“2”“3”这三个文件就是“E:psd”这个目录里的文件,“目录文件”指的是“1 2 3”这三个文件。 “E:psd”是“1 2 3”这三个文件所在的目录,“文件目录”指的是“E:psd”这个目录。 不同的就是“目录文件”指的是某些“文件”,“目录”只是定义这些文件存放的位置。 “文件目录”指的是某个目录,“文件”只是定义这个目录里具有哪些文件。 前者定义的是“文件”后者定义的是“目录”
3.2.1.3、字符设备文件(c    character)
3.2.1.4、块设备文件(b    block)
(1)设备文件对应的是硬件设备,也就是说这个文件虽然在文件系统中存在,但是并不是真正存在于硬盘上的一个文件,而是文件系统虚拟制造出来的(叫虚拟文件系统,如/dev            /sys /proc等)
(2)虚拟文件系统中的文件大多数不能或者说不用直接读写的,而是用一些特殊的API产生或者使用的,具体在驱动阶段会详解。
 
3.2.1.5、管道文件(p     pipe)
3.2.1.6、套接字文件(s    socket):这种文件类型用于进程间的网络通信
3.2.1.7、符号链接文件(l    link):这种文件类型指向另一个文件
 
【普通文件是一个"-",目录文件是一个"d"标识。字符设备文件是"c",块设备文件"b",管道文件“p”,套接字文件“S”,符号链接文件“l”。 】
3.2.2.常用文件属性获取
3.2.2.1、stat、fstat、lstat函数简介
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);   //带有const的是输入型参数,查看一个未打开的文件属性
int fstat(int fd, struct stat *buf);  //查看一个已经打开的文件属性
int lstat(const char *path, struct stat *buf);  //查阅的是符号链接文件本身的属性。
(1)每个文件中都附带了这个文件的一些属性(属性信息是存在于文件本身中的,但是它不像文件的内容一样可以被vi打开看到,属性信息只能被专用的API打开看到)
(2)【文件属性信息】查看的API有三个:stat、fstat、lstat,三个作用一样,参数不同,细节略有不同。
(3)linux命令行下还可以去用stat命令去查看文件属性信息,实际上stat命令内部就是使用【stat系统调用】来实现的。
(4)
【int stat(const char *path, struct stat *buf);   //带有const的是输入型参数
stat这个API的作用就是让内核将我们要查找属性的文件的属性信息结构体的值放入我们传递给stat函数的buf中,当stat这个API调用从内核返回的时候buf中就被填充了文件的正确的属性信息,然后我们通过查看buf这种结构体变量的元素就可以得知这个文件的各种属性了。
(5)fstat和stat的区别是:stat是从文件名出发得到文件属性信息结构体(命令使用时,直接就是stat FILENAME),而fstat是从一个已经打开的文件fd出发得到一个文件的属性信息。所以用的时候如果文件没有打开(我们并不想打开文件操作而只是希望得到文件属性)那就用stat,如果文件已经被打开了然后要属性那就用fstat效率会更高(stat是从磁盘去读取文件的,而fstat是从内存读取动态文件的)。
(6)lstat和stat/fstat的差别在于:对于符号链接文件,stat和fstat查阅的是【符号链接文件指向的那个文件的属性】,而lstat查阅的是符号链接文件本身的属性。
 
3.2.2.2、struct stat结构体简介          【 man  2   stat 】
(1)struct stat是内核定义的一个结构体,在<sys/stat.h>中声明,所以我们可以用。这个结构体中的所有元素加起来就是我们的【文件属性信息】。
int stat(const char *path, struct stat *buf);   //带有const的是输入型参数,后面是一个结构体指针
 
           struct stat {
               dev_t     st_dev;     /* ID of device containing file */
               ino_t     st_ino;     /* inode number */
               mode_t    st_mode;    /* protection   查看一个文件的权限信息*/
               nlink_t   st_nlink;   /* number of hard links */  硬连接号码
               uid_t     st_uid;     /* user ID of owner */
               gid_t     st_gid;     /* group ID of owner */
               dev_t     st_rdev;    /* device ID (if special file) */
               off_t     st_size;    /* total size, in bytes  总共大小*/
               blksize_t st_blksize; /* blocksize for filesystem I/O */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
               time_t    st_atime;   /* time of last access */
               time_t    st_mtime;   /* time of last modification */
               time_t    st_ctime;   /* time of last status change */
           };
 
一个文件1.file_shuxing_test1.c的属性信息:
File: ‘1.file_shuxing_test1.c’
Size: 173           Blocks: 1          IO Block: 1024   regular file
Device: 18h/24d    Inode: 66          Links: 1
Access: (0777/-rwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-04-11 02:03:14.242978200 +0000
Modify: 2016-04-11 03:03:35.280089700 +0000
Change: 2016-04-11 03:03:35.280089700 +0000
 Birth: -
 
3.2.2.3、写个程序来查看一些常见属性信息
代码如下:
int stat(const char *path, struct stat *buf);   //带有const的是输入型参数,后面是一个结构体指针
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define NAME     "1.txt"
int main(void)
{
    int ret = -1;
    struct stat buf;                             //定义一个结构体buf变量,buf只是个变量名而已,我也可以定义成其他名字
    memset(&buf, 0, sizeof(buf));            // memset后buf中全是0
    ret = stat(NAME, &buf);                // stat后buf中有内容了
    if (ret < 0)
    {
        perror("stat");
        exit(-1);
    }
    // 成功获取了stat结构体,从中可以得到各种属性信息了
    printf("inode = %d. ", buf.st_ino);
    printf("size = %d bytes. ", buf.st_size);
    printf("st_blksize = %d. ", buf.st_blksize);
    return 0;
}
 
 
 
3.2.3.stat函数的应用案例
   stat结构体
 struct stat {
               dev_t     st_dev;     /* ID of device containing file */
               ino_t     st_ino;     /* inode number */
               mode_t    st_mode;    /* protection */
               nlink_t   st_nlink;   /* number of hard links */
               uid_t     st_uid;     /* user ID of owner */
               gid_t     st_gid;     /* group ID of owner */
               dev_t     st_rdev;    /* device ID (if special file) */
               off_t     st_size;    /* total size, in bytes */
               blksize_t st_blksize; /* blocksize for filesystem I/O */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
               time_t    st_atime;   /* time of last access */
               time_t    st_mtime;   /* time of last modification */
               time_t    st_ctime;   /* time of last status change */
           };
 
3.2.3.1、用代码判断文件类型
(1)文件类型就是-、d、l····
(2)文件属性中的文件类型标志在struct stat结构体的mode_t    st_mode元素中,这个元素其实是一个按位来定义的一个位标志(有点类似于ARM CPU的CPSR寄存器的模式位定义)。这个东西有很多个标志位共同构成,记录了很多信息,如果要查找文件权限功能时按位&操作就知道结果了,但是因为这些位定义不容易记住,因此linux系统给大家事先定义好了很多宏来进行相应操作,我们【只要把stat结构体中的mode_t    st_mode元素作为参数传给这些宏中】,根据宏的返回值就可以判断文件类型等。
/*
linux系统给大家事先定义好了很多宏:我们把mode_t    st_mode元素作为参数传给这些宏中
           S_ISREG(m)  is it a regular file?
 
           S_ISDIR(m)  directory?
 
           S_ISCHR(m)  character device?
 
           S_ISBLK(m)  block device?
 
           S_ISFIFO(m) FIFO (named pipe)?
 
           S_ISLNK(m)  symbolic link?  (Not in POSIX.1-1996.)    //是不是一个符号链接文件
 
           S_ISSOCK(m) socket?  (Not in POSIX.1-1996.)
*/
(3)譬如S_ISREG宏返回值是1表示这个文件是一个普通文件,如果文件不是普通文件则返回值是0.
 
3.2.3.2、用代码判断文件权限设置
(1)st_mode中除了记录了文件类型之外,还记录了一个重要信息:文件权限。
(2)linux并没有给文件权限测试提供宏操作,而只是提供了【位掩码】,所以我们只能用位掩码来自己判断是否具有相应权限。
/*
                                    位掩码
           S_IFMT        0170000   bit mask for the file type bit fields
           S_IFSOCK   0140000   socket
           S_IFLNK    0120000   symbolic link
           S_IFREG    0100000   regular file
           S_IFBLK    0060000   block device
           S_IFDIR    0040000   directory
           S_IFCHR    0020000   character device
           S_IFIFO    0010000   FIFO
           S_ISUID    0004000   set-user-ID bit
           S_ISGID    0002000   set-group-ID bit (see below)
           S_ISVTX    0001000   sticky bit (see below)
           S_IRWXU    00700     mask for file owner permissions
           S_IRUSR    00400     owner has read permission
           S_IWUSR    00200     owner has write permission
           S_IXUSR    00100     owner has execute permission
           S_IRWXG    00070     mask for group permissions
           S_IRGRP    00040     group has read permission
           S_IWGRP    00020     group has write permission
 
           S_IXGRP    00010     group has execute permission
           S_IRWXO    00007     mask for permissions for others (not in group)
           S_IROTH    00004     others have read permission
           S_IWOTH    00002     others have write permission
           S_IXOTH    00001     others have execute permission
*/
 
 
代码测试:
/*
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
 
 
#define NAME "1.txt"
 
int main(void)
{
    int ret = -1;
    struct stat buf;
 
    memset(&buf, 0, sizeof(buf));        // memset后buf中全是0
    ret = stat(NAME, &buf);                // stat后buf中有内容了
    if (ret < 0)
    {
        perror("stat");
        exit(-1);
    }
 
#if 0   
    // 判断这个文件属性
    //int result = S_ISREG(buf.st_mode);
       int result = S_ISDIR(buf.st_mode);
       printf("result = %d ", result);
#endif
 
    // 文件权限测试
    //unsigned int result = (buf.st_mode & S_IRWXU) >> 8;
    unsigned int result = ((buf.st_mode & S_IRUSR)? 1: 0);
    printf("file owner: %u. ", result);
    return 0;
}
*/
 
-----------------------------------------------------------------------------------------------------------------------------------------------------------
3.2.4.文件权限管理1
3.2.4.1、st_mode中记录的文件权限位
(1)st_mode本质上是一个32位的二进制数(类型就是unsinged int),这个数里的每一个位表示一个含义。
(2)【文件类型和文件的权限】都记录在st_mode中。我们查找文件的权限的时候使用专门的掩码去取出相应的位即可得知相应的信息。
 
3.2.4.2、ls -l打印出的权限列表
(1)
123456789一共9位,3个一组。第一组三个表示文件的属主(owner、user)对该文件的可读、可写、可执行权限;第2组3个位表示文件的属主所在的组(group)对该文件的权限;第3组3个位表示其他用户(others其他组里的用户)对该文件的权限。
(2)属主就是这个文件属于谁,一般来说文件创建时属主就是创建这个文件的那个用户。但是我们一个文件创建之后还可以用chown命令去修改一个文件的属主,还可以用chgrp命令去修改一个文件所在的组。
3.2.4.3、文件操作时的权限检查规则
(1)一个程序a.out被执行,a.out中试图去操作一个文件1.txt,这时候如何判定a.out是否具有对1.txt的某种操作权限呢?
(2)判定方法是:首先1.txt具有9个权限位,规定了3种人(user、group、others)对该文件的操作权限。所以我们判定1.txt是否能被a.out来操作,关键先搞清楚a.out对1.txt到底算哪种人。准确的说是看a.out被谁执行,也就是当前程序(进程)是哪个用户的进程。
(3)刚才上面说的是我的分析,到底对不对还得验证。
代码:
/*
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#define NAME "1.txt"
 
int main(void)
{
    int ret = -1;
 
    ret = open(NAME, O_RDONLY);
    if (ret > 0)
    {
        printf("可读      ");
        close(ret);
 
    }
    else
    {
        perror("read");
    }
 
 
    ret = open(NAME, O_WRONLY);
    if (ret > 0)
    {
        printf("可写      ");
        close(ret);
    }
    else
        perror("write");
 
    return 0;
}
*/
-----------------------------------------------------------------------------------------------------------------------------------------------------------
3.2.5.文件权限管理2
3.2.5.1、access函数检查权限设置    man 2 access     [R_OK  W_OK  X_OK  F_OK]     返回值为0或-1
【 R_OK, W_OK, and X_OK test whether the file exists and grants read, write, and execute permissions, respectively.】
【The check is done using the calling process's real UID and GID】
【 On success (all requested permissions granted, or mode is F_OK and the file exists), zero is returned.  On error (at least one bit in mode  asked  for  a  permission that is denied, or mode is F_OK and the file does not exist, or some other error occurred), -1 is returned, and errno is set appropriately.】
【】
(1)文本权限管控其实蛮复杂,一般很难确定对一个文件是否具有某种权限(因为不但跟文件本身有关系,还与谁执行这个文件有关系)。设计优秀的软件应该是:在操作某个文件之前先判断当前是否有权限做这个操作,如果有再做如果没有则提供错误信息给用户。
(2)access函数可以测试得到当前执行程序的那个用户在当前那个环境下对目标文件是否具有某种操作权限。
【 int access(const char *pathname, int mode);】
代码测试:
/*
#include <stdio.h>
#include <unistd.h>
#define NAME     "3.txt"
int main(void)
{
    int ret = -1;
    ret = access(NAME, F_OK);
    if (ret < 0)
    {
        printf("文件不存在 ");
        return -1;
    }
    else
    {
        printf("文件存在    ");
    }
 
    ret = access(NAME, R_OK);
    if (ret < 0)
    {
        printf("不可读 ");
    }
    else
    {
        printf("可读 ");
    }
 
    ret = access(NAME, W_OK);
    if (ret < 0)
    {
        printf("不可写 ");
    }
    else
    {
        printf("可写 ");
    }
 
    ret = access(NAME, X_OK);
    if (ret < 0)
    {
        printf("不可执行 ");
    }
    else
    {
        printf("可执行 ");
    }   
    return 0;
}
*/
 
3.2.5.2、chmod/fchmod与权限修改
(1)chmod是一个linux命令,用来修改文件的各种权限属性。chmod命令【只有root用户】才有权利去执行修改,一种安全机制。
(2)chmod命令其实内部是用linux的一个叫【chmod的API】实现的。
fchmod是对一个已经打开的文件进行操作的。
 /*               man  2  chmod
 #include <sys/stat.h>
 int chmod(const char *path, mode_t mode);
 int fchmod(int fd, mode_t mode);
*/
代码:
/*
#include <stdio.h>
#include <sys/stat.h>
 
int main(int argc, char **argv)
{
    int ret = -1;
    if (argc != 2)           //   ./a.out  test.c
    {
        printf("usage: %s filename ", argv[0]);
        return -1;
    }
    ret = chmod(argv[1], S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWOTH);
    if (ret < 0)
    {
        perror("chmod");
        return -1;
    }
    return 0;
}
*/ 
【可读 4 可写2 可执行1  chmod 777 最高权限  XXX用户、组、其他组】
3.2.5.3、chown/fchown/lchown与属主修改
(1)linux中有个chown命令来修改文件属主
(2)chown命令是用chown API实现的
(3)chgrp是修改组的
补充:
$ chmod u+x file                      给file的属主增加执行权限
$ chmod 751 file                      给file的属主分配读、写、执行(7)的权限,给file的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限
$ chmod u=rwx,g=rx,o=x file      上例的另一种形式
$ chmod =r file                     为所有用户分配读权限
$ chmod 444 file                   同上例
$ chmod a-wx,a+r   file          同上例
$ chmod -R u+r directory           递归地给directory目录下所有文件和子目录的属主分配读的权限
$ chmod 4755                            设置用ID,给属主分配读、写和执行权限,给组和其他用户分配读、执行的权限。
3.2.5.4、umask与文件权限掩码
(1)文件掩码【是linux系统中维护的一个全局设置】,umask的作用是用来设定我们系统中新创建的文件的默认权限的。
(2)umask命令就是用umask API实现的
 
-----------------------------------------------------------------------------------------------------------------------------------------------------------
3.2.6.读取目录文件(目录文件就是一个特殊的文件)
3.2.6.1、opendir与readdir函数API来打开和读取一个目录文件
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);           //文件指针
DIR *fdopendir(int fd);
 
 
 
【#include <dirent.h>
struct dirent *readdir(DIR *dirp);                       //结构体指针,DIR *dirp是一个目录
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);】
(1)opendir打开一个目录后得到一个DIR类型的【指针】给readdir使用
(2)readdir函数调用一次就会返回一个struct dirent类型的结构体 指针,这个指针指向一个struct dirent类型的结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。    【man 3 readdir】
/*
struct dirent {
               ino_t          d_ino;       /* inode number */
               off_t          d_off;       /* not an offset; see NOTES */
               unsigned short d_reclen;    /* length of this record */
               unsigned char  d_type;      /* type of file; not supported           文件夹类型
                                              by all filesystem types */
               char           d_name[256]; /* filename */                                 
           };
*/
 
(3)readdir调用一次只能读出一个目录项,要想读出目录中所有的目录项必须【多次调用readdir函数】。readdir函数内部会记住【哪个目录项已经被读过了哪个还没读】,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
 
3.2.6.2、dirent结构体
比较重要的就是【type和name】两个选项。
3.2.6.3、读取目录实战演练
代码示例:
#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
//DIR *opendir(const char *name);           //文件指针
//struct dirent *readdir(DIR *dirp);       
#define NAME  "./4.进程"
void main()
{
    struct dirent *p1;
    DIR *p=NULL;
    p=opendir(NAME);
    if(p==NULL)
    {
        perror("opendir");
        _exit(-1);
        }
while ((p1 = readdir(p)) != NULL) 
    printf("%s ", p1->d_name);     //打印出该目录下的所有内容
    printf("%d ", p1->d_ino);     //打印出该目录下所有文件的inode号
    //printf("%c ", p1->d_type);     //打印出该目录下所有文件的类型
if (p1->d_type == DT_REG)    //判断文件类型This is a regular file.
     {
                printf("是普通文件 ");
    }
    else
   {
     printf("不是普通文件 ");
   }
}
 
 
3.2.6.4、可重入函数介绍
(1)有些函数是可重入的有些是不可重入的,具体概念可以去百度。
可重入函数:指一个可以被多个任务调用的函数,这种函数在不同的任务调用的时候不会改变或者影响其他任务调用该函数时的数据,这种是安全的设计架构。
(2)readdir函数和我们前面接触的一些函数是不同的,首先readdir函数直接返回了一个【结构体变量指针,这个指针指向一个结构体,这个结构体中包含了该目录下文件的类型及名称等内容】,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir其实readir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。【这个设计方法是readdir不可重入的关键。】
(3)readdir在多次调用时【是有关联】的,这个关联也标明readdir函数是不可重入的。
(4)库函数中有一些函数当年刚开始提供时都是不可重入的,后来意识到这种方式不安全,所以重新封装了C库,提供了对应的可重复版本(一般是不可重入版本函数名_r)
 
代码:
/*
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char **argv)
{
    DIR *pDir = NULL;                 //指向一个目录文件opendir
    struct dirent * pEnt = NULL;           //readdir返回的结构体指针
    unsigned int cnt = 0;               //计算文件夹下有多少个文件
 
    if (argc != 2)
    {
        printf("usage: %s dirname ", argv[0]);
        return -1;
    }
 
    pDir = opendir(argv[1]);
    if (NULL == pDir)
    {
        perror("opendir");
        return -1;
    }
    while (1)
    {
        pEnt = readdir(pDir);                   //readdir函数返回的一个结构体指针,这个指针指向一个存放目录下文件(子文件)的结构体
        if(pEnt != NULL) //当pEnt == NULL时,表示已经读取完毕
        {
            // 还有子文件,在此处理子文件
            printf("name:[%s]    ,", pEnt->d_name);
            cnt++;
            if (pEnt->d_type == DT_REG)              //判断文件类型This is a regular file.
            {
                printf("是普通文件 ");
            }
            else
            {
                printf("不是普通文件 ");
            }
        }
        else
        {
            break;
        }
    };
    printf("总文件数为:%d ", cnt);
    return 0;
}           
 
*/
root@ubuntu:/mnt/hgfs/Winshare/1.Linux应用编程和网络编程/2.file_shuxing# ./a.out  ../1.file_io/
name:[.]    ,不是普通文件
name:[..]    ,不是普通文件
name:[1.txt]    ,是普通文件
name:[a.out]    ,是普通文件
name:[file1.c]    ,是普通文件
name:[test.txt]    ,是普通文件
总文件数为:6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/wycBlog/p/7610886.html