linux应用编程(3)文件属性

(一)文件属性(Linux中一切皆文件

1.linux中各种文件类型

在这里插入图片描述

例子

中文linux中的表示英文
普通文件-regular file
目录文件ddirectory
字符设备文件ccharacter
块设备文件bblock
管道文件ppipe
套接字文件ssocket
符号链接文件llink
  1. 普通文件(- regular file)
  • 文本文件: 文件中的内容是由文本构成的,文本指的是ASCII码字符。文件里的内容本质上都是数字(不管什么文件内容本质上都是数字,因为计算机中本身就只有1和0),而文本文件中的数字本身应该被理解为这个数字对应的ASCII码。常见的.c文件, .h文件 .txt文件等都是文本文件。文本文件的好处就是可以被人轻松读懂和编写。所以说文本文件天生就是为人类发明的。
  • 二进制文件:二进制文件中存储的本质上也是数字,只不过这些数字并不是文字的编码数字,而是就是真正的数字。常见的可执行程序文件(gcc编译生成的a.out,arm-linux-gcc编译连接生成的.bin)都是二进制文件。
  • 对比:从本质上来看(就是刨除文件属性和内容的理解)文本文件和二进制文件并没有任何区别。都是一个文件里面存放了数字。 区别是理解方式不同,如果把这些数字就当作数字处理则就是二进制文件,如果把这些数字按照某种编码格式去解码成文本字符,则就是文本文件。
  • 我们如何知道一个文件是文件文件还是二进制文件?在linux系统层面是不区分这两个的(譬如之前学过的open、read、write等方法操作文件文件和二进制文件时一点区别都没有),所以我们无法从文件本身准确知道文件属于哪种 ,我们只能本来就知道这个文件的类型然后用这种类型的用法去用他。有时候会用一些后缀名来人为的标记文件的类型。
  • 使用文本文件时,常规用法就是用文本文件编辑器去打开它、编辑它。常见的文本文件编辑器如vim、gedit、notepad++、SourceInsight等,我们用这些文本文件编辑器去打开文件的时候,编辑器会read读出文件二进制数字内容,然后按照编码格式去解码将其还原成文字展现给我们。如果用文本文件编辑器去打开一个二进制文件会如何?这时候编辑器就以为这个二进制文件还是文本文件然后试图去将其解码成文字,但是解码过程很多数字并不对应有意义的文字所以成了乱码。
  • 反过来用二进制阅读工具去读取文本文件会怎么样?得出的就是文本文字所对应的二进制的编码。
  1. 目录文件(d directory)
  • 目录就是文件夹,文件夹在linux中也是一种文件,不过是特殊文件。用vi打开一个文件夹就能看到,文件夹其实也是一种特殊文件 ,里面存的内容包括这个文件的路径,还有文件夹里面的文件列表。

  • 但是文件夹这种文件比较特殊,本身并不适合用普通的方式来读写。linux中是使用特殊的一些API来专门读写文件夹的。

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

(二)常用文件属性获取

1.stat、fstat、lstat函数简介

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

2.struct stat结构体简介

  1. struct stat是内核定义的一个结构体,在<sys/stat.h>中声明,所以我们可以用。这个结构体中的所有元素加起来就是我们的文件属性信息。
    在这里插入图片描述
man 2 stat 中对stat结构体的解释

(三)文件权限获取

1.access函数(测试文件权限)

int access(const char *pathname, int mode);
/*
DESCRIPTION
       access() checks whether the calling process can access the file pathname.  If pathname is a symbolic link, it is dereferenced.

       The mode specifies the accessibility check(s) to be performed, and is either the value F_OK, or a mask consisting of the bitwise OR of one or more of R_OK, W_OK, and X_OK.  F_OK tests
       for the existence of the file.  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, rather than the effective IDs as is done when actually attempting an operation (e.g., open(2)) on the file.  Similarly,
       for the root user, the check uses the set of permitted capabilities rather than the set of effective capabilities; and for non-root users, the check uses an empty set of capabilities.

       This  allows  set-user-ID  programs  and  capability-endowed  programs  to  easily  determine  the  invoking  user's  authority.   In  other words, access() does not answer the "can I
       read/write/execute this file?" question.  It answers a slightly different question: "(assuming I'm a setuid binary) can the user who invoked me read/write/execute this  file?",  which
       gives set-user-ID programs the possibility to prevent malicious users from causing them to read files which users shouldn't be able to read.

       If  the  calling  process  is  privileged (i.e., its real UID is zero), then an X_OK check is successful for a regular file if execute permission is enabled for any of the file owner,group, or other.

*/
  • access函数可以测试得到当前执行程序的那个用户在当前那个环境下对目标文件是否具有某种操作权限。

2.应用

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define FLIENAME "3.txt"
int main (void)
{
	int ret = -1;
//第一个参数是文件名,第二个参数是需要检查的权限或文件是否存在
	ret = access(FLIENAME, F_OK);
	if(0 == ret)
	{
		printf("flie exit\n");
	}
	else
	{
		printf("flie no exit\n");
		_exit(-1);
	}
	ret = access(FLIENAME, R_OK);
	if (0 == ret)
	{
		printf("R_OK\n");
	}
	else
	{
		printf("R_ERROR\n");
	}
	ret = access(FLIENAME, W_OK);
	if (0 == ret)
	{
		printf("W_OK\n");
	}
	else
	{
		printf("W_ERROR\n");
	}

	return 0;
}

在这里插入图片描述

代码运行结果

(四)文件权限修改

1.使用chmod命令

  1. chmod是一个linux命令,用来修改文件的各种权限属性。
  2. chmod命令其实内部是用linux的一个叫chmod的API 实现的。

2.使用chmod函数

int chmod(const char *pathname, mode_t mode);//用法类似access函数
  1. chmod/fchmod的区别:
  • chmod() changes the permissions of the file specified whose pathname is given in pathname, which is dereferenced if it is a symbolic link.
  • fchmod() changes the permissions of the file referred to by the open file descriptor fd.
  • 总结:chmod打开静态文件(保存在硬盘中),fchmod打开动态文件(使用open函数打开的文件)(加载到内存中)。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define FLIENAME "3.txt"
int main (void)
{
	//设置文件为owner可读写 group可写
	chmod(FLIENAME, S_IRUSR | S_IWGRP | S_IWUSR);
	return 0;
}

在这里插入图片描述

代码运行结果
  • 没有给予权限的权限位全部被清除

3.使用umask命令

  1. 在linux系统中,我们创建一个新的文件或者目录的时候,这些新的文件或目录都会有默认的访问权限,umask命令与文件和目录的默认访问权限有关。若用户创建一个文件,则文件的默认访问权限为 -rw-rw-rw-,创建目录的默认权限 drwxrwxrwx而umask值则表明了需要从默认权限中去掉哪些权限来成为最终的默认权限值。

    在这里插入图片描述

    例子

  • 其中第一个0与特殊权限有关,可以暂时不用理会,后三位420则与普通权限(rwx)有关,其中420中第一个4与用户(user)权限有关,表示从用户权限减4,也就是权限去掉r,第二个2与组权限(group)有关,表示从组的权限减2,也就是权限去掉w,最后一位0则与系统中其他用户(others)的权限有关,权限减去0,即权限不变,所以默认权限为rw,则创建文件的最终默认权限为 --w-r-rw-

(五)读取目录文件

1.readdir和opendir函数

DIR *opendir(const char *name);
/*
The opendir() function opens a directory stream corresponding to the directory name, and returns a pointer to the directory stream.  The stream is positioned at the first entry in the directory.
*/
struct dirent *readdir(DIR *dirp);
/*
The  readdir()  function returns a pointer to a dirent structure representing the next directory entry in the directory stream pointed to by dirp.  It returns NULL on reaching the end of the directory stream or if an error occurred.
*/
//dirent结构体
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 */
           };
  1. opendir打开一个目录后得到一个DIR类型的指针给readdir使用
  2. readdir函数调用一次就会返回一个struct dirent类型的指针,这个指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。
  3. readdir调用一次只能读出一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。 readdir函数内部户记住哪个目录项已经被读过了哪个还没读,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
	DIR *pDir = NULL;
	struct dirent *pEnt = NULL;
	if(argc != 2)
	{
		printf("usage: %s dirname\n", argv[0]);
		return -1;
	}
	 //DIR *opendir(const char *name);
	 //struct dirent *readdir(DIR *dirp);
	pDir = opendir(argv[1]);
	while(1)
	{
		pEnt = readdir(pDir);
		if(NULL != pEnt)
		{
			printf("file name is [%s]\n", pEnt->d_name);
		}
		else
		{
			break;
		}
	}

	return 0;
}

在这里插入图片描述

运行结果

2.可重入函数与不可重入函数

  • 不可重入函数: 在函数中如果我们使用静态变量了,导致产生中断调用别的函数的 过程中可能还会调用这个函数,于是原来的 静态变量被在这里改变了,然后返回主体函数,用着的那个静态变量就被改变了,导致错误。这类函数我们称为不可重入函数

  • 可重入函数: 如果是在函数体内动态申请内存的话,即便新的线程调用这个函数也没事,因为新的线程使用的是新的函数的 新申请的动态内存(静态变量只有一份,所以多线程对于函数体内的静态变量改变会有无法修复的结果),所以这类函数就是可重入函数

struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

//The  readdir_r() function is a reentrant version of readdir(). 
  1. readdir函数和我们前面接触的一些函数是不同的,首先readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir其实readir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法是readdir不可重入的关键。
  2. readdir在多次调用时是有关联的,这个关联也标明readdir函数是不可重入的。
  3. 库函数中有一些函数当年刚开始提供时都是不可重入的,后来意识到这种方式不安全,所以重新封装了C库,提供了对应的可重复版本(一般是不可重入版本函数名加_r)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值