Linux系统编程之获取文件信息

         利用系统调用stat()、lstat()以及fstat(),可获取与文件有关的信息,其中大部分提取自文件i节点。以上3个系统调用之间仅有的区别在于对文件的描述方式不同。

         1  stat()返回所命名文件的相关信息。

         2  lstat()与stat()类似,区别在于如果文件属于符号链接,那么所返回的信息针对的是符号链接自身(而非符号链接所指向的文件)。

         3  fstat()则返回由某个打开文件描述符所指代文件的相关信息。

         系统调用stat()和lstat()不需要对所操作的文件本身拥有任何权限,但针对指定pathname的父目录要有执行(搜索)权限。而只要为它提供有效的文件描述符,fstat()系统调用总是成功的。

         上述所有系统调用都会在缓冲区中返回一个由statbuf指向的stat结构,其格式如下:

         Linux系统编程之获取文件信息_第1张图片

设备ID和i节点号

         st_dev字段标识文件所驻留的设备。st_ino字段包含了文件的i节点号。利用这两个字段,可以在所有文件系统中唯一表示某个文件。

         如果是针对设备的i节点,那么st_rdev字段则包含设备的主、辅ID。利用宏major()和minor(),可以提取主、辅ID。在Linux系统上,要使用这两个宏,需要定义_BSD_SOURCE宏,然后include定义这两个宏的头文件

         Linux系统编程之获取文件信息_第2张图片

         由于major()和minor()所返回的整型值大小随UINX实现的不同而各有不用。为保证可移植性,打印时总是将返回值强制转换为long。

 

文件所有权

         st_uid和st_gid字段分别表示文件的属主(用户ID)和属组(组ID)。

 

链接数

         st_nlink字段包含了指向文件的(硬)链接数。

 

文件类型及权限

         st_mode字段内含有位掩码,起表示文件类型和指定文件权限的双重作用。下图为该字段所含各位的布局情况。 

文件类型

权限

 

 

 

 

U

G

T

R

W

X

R

W

X

R

W

X

         Linux使用了st_mode字段中的4位来标识文件类型位。st_mode字段与常量S_IFMT相与(&),可从该字段中提取出文件类型。将计算结果与一系列常量进行比较,即可确定文件类型:

         if((statbuf.st_mode & S_IFMT) == S_IFREG)

                   printf(“regularfile\n”);

         在Linux中可利用标准宏将其简化:

         if(S_ISREG(statbuf.st_mode))

                   printf(“regularfile\n”);

 

常  量

测  试  宏

文  件  类  型

S_IFREG

S_ISREG()

常规文件

S_IFDIR

S_ISDIR()

目录

S_IFCHR

S_ISCHR()

字符设备

S_IFBLK

S_ISBLK()

块设备

S_IFIFO

S_ISFIFO()

FIFO或管道

S_IFSOCK

S_ISSOCK()

套接字

S_IFLNK

S_ISLNK()

符号链接

针对stat结构中的st_mode来检查文件类型的宏

         想从中获取S_IFSOCK和S_ISSOCK()的定义,必须定义_BSD_SOURCE特性测试宏,或将_XOPEN_SOURCE定义为不小于500的值。

         st_mode字段的低12位定义了文件权限。最低9位分别用来表示文件属主、属组以及其他用户的读、写、执行权限。

 

文件大小、已分配块以及最优I/O块大小

         对于常规文件,st_size字段表示文件的字节数。对于符号链接,st_size字段则表示链接所指路径名的长度,以字节为单位。对于共享内存对象,该字段则表示对象的大小。

         st_blocks字段表示分配给文件的总块数,块大小为512字节,其中包括了为指针块所分配的空间。st_blocks字段记录了实际分配给文件的磁盘块数量。如果文件内含空洞,该值将小于从相应文件字节数字段(st_size)的值。

         st_blksize字段所指并非底层文件系统的块大小,而是针对文件系统上文件进行I/O操作时的最优块大小(以字节为单位)。一般而言,st_blksize的返回值为4096。

 

文件时间戳

         st_time、st_mtime和st_ctime字段,分别记录了对文件的上次访问时间、上次修改时间以及文件状态发送改变的上次时间。这3个字段的类型都是time_t,记录了自新纪元(Epoch)以来的秒数。

 

示例程序

(获取并解释文件的stat信息)

#define _BSD_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FP_SPECIAL 1
#define STR_SIZE sizeof("rwxrwxrwx")

typedef enum { FALSE, TRUE } Boolean;

static char *filePermStr(mode_t perm, int flags)
{
	static char str[STR_SIZE];
	snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c",
		(perm & S_IRUSR) ? 'r' : '-', (perm & S_IWUSR) ? 'w' : '-',
		(perm & S_IXUSR) ? 
			(((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x') :
			(((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'),
		(perm & S_IRGRP) ? 'r' : '-', (perm & S_IWGRP) ? 'w' : '-',
		(perm & S_IXGRP) ? 
			(((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x') :
			(((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'),
		(perm & S_IROTH) ? 'r' : '-', (perm & S_IWOTH) ? 'w' : '-',
		(perm & S_IXOTH) ? 
			(((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 't' : 'x') :
			(((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'T' : '-'));
			
	return str;
}

static void showStatInfo(struct stat *st)
{
	printf("File type:			");
	
	switch(st->st_mode & S_IFMT)
	{
		case S_IFREG:	printf("regular file\n");		break;
		case S_IFDIR:	printf("directory\n");			break;
		case S_IFCHR:	printf("character device\n");	break;
		case S_IFBLK:	printf("block device\n");		break;
		case S_IFLNK:	printf("symbolic (soft) link\n");	break;
		case S_IFIFO:	printf("FIFO or pipe\n");		break;
		case S_IFSOCK:	printf("socket\n");				break;
		default:		printf("unknown file type?\n");	break;
	}
	
	printf("Device containing i-node: 	major=%ld	minor=%ld\n", 
		(long) major(st->st_dev), (long) minor(st->st_dev));
		
	printf("I-node number:			%ld\n", (long) st->st_ino);
	printf("Mode:				%lo (%s)\n", (unsigned long) st->st_mode, 
		filePermStr(st->st_mode, 0));
		
	if (st->st_mode & (S_ISUID| S_ISGID| S_ISVTX))
		printf("	special bits set:	%s%s%s\n",
			(st->st_mode & S_ISUID) ? "set-UID " : "",
			(st->st_mode & S_ISGID) ? "set-GID " : "",
			(st->st_mode & S_ISVTX) ? "sticky " : "");
			
	printf("Number of (hard) links:		%ld\n", (long) st->st_nlink);
	printf("Ownership:			UID=%ld	GID=%ld\n",
		(long) st->st_uid, (long) st->st_gid);
		
	if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
		printf("Device number (st_rdev):		major=%ld; minor=%ld\n",
			(long) major(st->st_rdev), (long) minor(st->st_rdev));
			
	printf("File size:			%lld bytes\n", (long long) st->st_size);
	printf("Optimal I/O block size:		%ld bytes\n", (long) st->st_blksize);
	printf("512B blocks allocated:		%lld\n", (long long) st->st_blocks);
	printf("Last file access:		%s\n", ctime(&st->st_atime));
	printf("Last file modification:		%s\n", ctime(&st->st_mtime));
	printf("Last status change:		%s\n", ctime(&st->st_ctime));
}

int main(int argc, char *argv[])
{
	struct stat st;
	Boolean statLink;
	int fname;
	
	statLink = (argc > 1) && strcmp(argv[1], "-l") == 0;
	
	fname = statLink ? 2: 1;
	
	if (fname >= argc || (argc > 1 && strcmp(argv[1], "--help") == 0))
		printf("%s [-l] file\n 		-l = use lstat() instead of stat()\n", argv[0]);
			
	if (statLink)
	{
		if (lstat(argv[fname], &st) == -1)
		{
			printf("lstat() operate failed!\n");
		}
	}
	else
	{
		if (stat(argv[fname], &st) == -1)
			printf("stat() operate failed!\n");
	}	
	showStatInfo(&st);
	exit(1);
}

以下是运行结果:

         Linux系统编程之获取文件信息_第3张图片


你可能感兴趣的:(Linux,C/C++)