文件属性介绍

1.linux中各种文件类型

2.普通文件(- regular file)
(1)文本文件。文件中的内容是由文本构成的,文本指的是ASCII码字符。文件里的内容本质上都是数字(不管什么文件内容本质上都是数字,因为计算机中本身就只有1和0),而文本文件中的数字本身应该被理解为这个数字对应的ASCII码。常见的.c文件, .h文件 .txt文件等都是文本文件。文本文件的好处就是可以被人轻松读懂和编写。所以说文本文件天生就是为人类发明的。
(2)二进制文件。二进制文件中存储的本质上也是数字,只不过这些数字并不是文字的编码数字,而是就是真正的数字。常见的可执行程序文件(gcc编译生成的a.out,arm-linux-gcc编译连接生成的.bin)都是二进制文件。
(3)对比:从本质上来看(就是刨除文件属性和内容的理解)文本文件和二进制文件并没有任何区别。都是一个文件里面存放了数字。区别是理解方式不同,如果把这些数字就当作数字处理则就是二进制文件,如果把这些数字按照某种编码格式去解码成文本字符,则就是文本文件。
(4)我们如何知道一个文件是文件文件还是二进制文件?在linux系统层面是不区分这两个的(譬如之前学过的open、read、write等方法操作文件文件和二进制文件时一点区别都没有),所以我们无法从文件本身准确知道文件属于哪种,我们只能本来就知道这个文件的类型然后用这种类型的用法去用他。有时候会用一些后缀名来人为的标记文件的类型。

3.目录文件(d directory)
(1)目录就是文件夹,文件夹在linux中也是一种文件,不过是特殊文件。
(2)linux中是使用特殊的一些API来专门读写文件夹的。

4.字符设备文件(c character)

5.块设备文件(b block)
(1)设备文件对应的是硬件设备,也就是说这个文件虽然在文件系统中存在,但是并不是真正存在于硬盘上的一个文件,而是文件系统虚拟制造出来的(叫虚拟文件系统,如/dev /sys /proc等)
(2)虚拟文件系统中的文件大多数不能或者说不用直接读写的,而是用一些特殊的API产生或者使用的,具体在驱动阶段会详解。

5.管道文件(p pipe)
6.套接字文件(s socket)
7.符号链接文件(l link)

8.常用文件属性
(1)文件属性信息查看的API有三个:stat、fstat、lstat,三个作用一样,参数不同,细节略有不同。
(2)linux命令行下还可以去用stat命令去查看文件属性信息,实际上stat命令内部就是使用stat系统调用来实现的。
(3)stat这个API的作用就是让内核将我们要查找属性的文件的属性信息结构体的值放入我们传递给stat函数的buf中,当stat这个API调用从内核返回的时候buf中就被填充了文件的正确的属性信息,然后我们通过查看buf这种结构体变量的元素就可以得知这个文件的各种属性了。
(4)fstat和stat的区别是:stat是从文件名出发得到文件属性信息结构体,而fstat是从一个已经打开的文件fd出发得到一个文件的属性信息。所以用的时候如果文件没有打开(我们并不想打开文件操作而只是希望得到文件属性)那就用stat,如果文件已经被打开了然后要属性那就用fstat效率会更高(stat是从磁盘去读取文件的,而fstat是从内存读取动态文件的)。
(5)lstat和stat/fstat的差别在于:对于符号链接文件,stat和fstat查阅的是符号链接文件指向的文件的属性,而lstat查阅的是符号链接文件本身的属性。

struct stat结构体简介
(1)struct stat是内核定义的一个结构体,在<sys/stat.h>中声明,所以我们可以用。这个结构体中的所有元素加起来就是我们的文件属性信息。
struct 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 file system 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 */ 最后一次改变该文件状态的时间   
};

stat结构体中的st_mode 则定义了下列数种情况:

    S_IFMT   0170000    文件类型的位遮罩
    S_IFSOCK 0140000    套接字
    S_IFLNK 0120000     符号连接
    S_IFREG 0100000     一般文件
    S_IFBLK 0060000     区块装置
    S_IFDIR 0040000     目录
    S_IFCHR 0020000     字符装置
    S_IFIFO 0010000     先进先出
​
    S_ISUID 04000     文件的(set user-id on execution)位
    S_ISGID 02000     文件的(set group-id on execution)位
    S_ISVTX 01000     文件的sticky位
​
    S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限
    S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限
    S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限
​
    S_IRGRP 00040             用户组具可读取权限
    S_IWGRP 00020             用户组具可写入权限
    S_IXGRP 00010             用户组具可执行权限
​
    S_IROTH 00004             其他用户具可读取权限
    S_IWOTH 00002             其他用户具可写入权限
    S_IXOTH 00001             其他用户具可执行权限
​
    上述的文件类型在POSIX中定义了检查这些类型的宏定义:
    S_ISLNK (st_mode)    判断是否为符号连接
    S_ISREG (st_mode)    是否为一般文件
    S_ISDIR (st_mode)    是否为目录
    S_ISCHR (st_mode)    是否为字符装置文件
    S_ISBLK (s3e)        是否为先进先出
    S_ISSOCK (st_mode)   是否为socket
    若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名,在linux中,最典型的就是这个/tmp目录啦。
​

stat作用:获取文件信息
返回值:成功返回0,失败返回-1;

#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\n", 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.\n", result);
	
	
	
	
	return 0;
}

9.ls -l打印出来的权限列表
(1)123456789一共9位,3个一组。第一组三个表示文件的属主(owner、user)对该文件的可读、可写、可执行权限;第2组3个位表示文件的属主所在的组(group)对该文件的权限;第3组3个位表示其他用户(others)对该文件的权限。
(2)属主就是这个文件属于谁,一般来说文件创建时属主就是创建这个文件的那个用户。但是我们一个文件创建之后还可以用chown命令去修改一个文件的属主,还可以用chgrp命令去修改一个文件所在的组。

10.文件权限管理
access函数检查权限设置
(1)access函数可以测试得到当前执行程序的那个用户在当前那个环境下对目标文件是否具有某种操作权限。

int access(const char *pathname, int mode);

access函数用来判断指定的文件或目录是否存在(F_OK),已存在的文件或目录是否有可读(R_OK)、可写(W_OK)、可执行(X_OK)权限。F_OK、R_OK、W_OK、X_OK这四种方式通过access函数中的第二个参数mode指定。如果指定的方式有效,则此函数返回0,否则返回-1。

#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("文件不存在 \n");
		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("不可执行 \n");
	}
	else
	{
		printf("可执行 \n");
	}	
	
	
	
	return 0;
}

11.chmod/fchmod与权限修改
(1)chmod是一个linux命令,用来修改文件的各种权限属性。chmod命令只有root用户才有权利去执行修改。
(2)chmod命令其实内部是用linux的一个叫chmod的API实现的。

#include <stdio.h>
#include <sys/stat.h>


int main(int argc, char **argv)
{
	int ret = -1;
	
	
	if (argc != 2)
	{
		printf("usage: %s filename\n", 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;
}

12.chown/fchown/lchown与属主修改
(1)linux中有个chown命令来修改文件属主
(2)chown命令是用chown API实现的

13.umask与文件权限掩码
(1)文件掩码是linux系统中维护的一个全局设置,umask的作用是用来设定我们系统中新创建的文件的默认权限的。
(2)umask命令就是用umask API实现的

14.读取目录文件
opendir与readdir函数
(1)opendir打开一个目录后得到一个DIR类型的指针给readdir使用
(2)readdir函数调用一次就会返回一个struct dirent类型的指针,这个指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。
(3)readdir调用一次只能读出一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。readdir函数内部户记住哪个目录项已经被读过了哪个还没读,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>


int main(int argc, char **argv)
{
	DIR *pDir = NULL;
	struct dirent * pEnt = NULL;
	unsigned int cnt = 0;
	
	if (argc != 2)
	{
		printf("usage: %s dirname\n", argv[0]);
		return -1;
	}
	
	pDir = opendir(argv[1]);
	if (NULL == pDir)
	{
		perror("opendir");
		return -1;
	}
	
	while (1)
	{
		pEnt = readdir(pDir);
		if(pEnt != NULL)
		{
			// 还有子文件,在此处理子文件
			printf("name:[%s]	,", pEnt->d_name);
			cnt++;
			if (pEnt->d_type == DT_REG)
			{
				printf("是普通文件\n");
			}
			else
			{
				printf("不是普通文件\n");
			}
		}
		else
		{
			break;
		}
	};
	printf("总文件数为:%d\n", cnt);
	
	
	return 0;
}

15.可重入函数介绍
(1)有些函数是可重入的有些是不可重入的
(2)readdir函数和我们前面接触的一些函数是不同的,首先readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir其实readir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法是readdir不可重入的关键。
(3)readdir在多次调用时是有关联的,这个关联也标明readdir函数是不可重入的。
(4)库函数中有一些函数当年刚开始提供时都是不可重入的,后来意识到这种方式不安全,所以重新封装了C库,提供了对应的可重复版本(一般是不可重入版本函数名_r)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值