UNIX环境编程学习笔记(6)——文件I/O之判断文件类型

时间:2021-01-14 15:20:12

lienhua34
2014-09-01

1 文件类型

我们平时最常接触的文件类型有普通文件(regular file)和目录(di-rectory file),但是 UNIX 系统提供了多种文件类型:

(1) 普通文件(regular file)

这种文件包含了某种形式的数据,这些数据无论是文件还是二进制对于 UNIX 内核而言都是一样的。对普通文件内容的解释有处理该文件的应用程序进行。

(2) 目录文件(directory file)

目录文件包含了其他文件的名字以及指向与这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读取该目录的内容,但是只有内核才能直接写目录文件。

(3) 块特殊文件(block special file)

这种文件类型提供对设备带缓冲的访问,每次访问以固定长度为单位进行。

(4) 字符特殊文件(character special file)

这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。

(5) FIFO

这种类型文件用于进程间通信。也称为命名管道(namedpipe)。

(6) 套接字(socket)

这种文件类型用于进程间的网络通信。

(7) 符号链接(symbolic link)

这种文件类型指向另一个文件。

我们如何判断一个文件的文件类型呢?我们可以先通过stat函数获取文件的属性信息,然后从其属性信息中判断该文件的文件类型。

2 获取文件属性信息的stat函数

UNIX系统提供了三个 stat 函数以获取文件的属性信息,包括文件类型、所有者、大小和修改时间等。

#include <sys/stat.h>

int stat(const char *restrict pathname, struct stat *restrict buf);

int fstat(int filedes, struct stat *buf);

int lstat(const char *restrict pathname, struct stat *restrict buf);

三个函数返回值:若成功则返回0,若出错则返回-1.

stat 函数获取与命名文件有关的信息结构。fstat 函数获取已在文件描述符filedes 上打开的文件的有关信息。lstat 函数类似于 stat 函数,但是当命名的文件是一个符号链接时,lstat 返回该符号链接的有关信息,而不是由该符号链接引用文件的信息。

第二个参数 buf 是指针,指向一个 struct stat 结构。这些函数填写由buf 指向的结构。struct stat 结构的基本形式如下:

struct stat {
mode_t st_mode;
/* file type & mode (permissions) */
ino_t st_ino;
/* i-node number (serial number) */
dev_t st_dev;
/* device number (file system) */
dev_t st_rdev;
/* device number for specail files */
nlink_t st_nlink;
/* number of links */
uid_t st_uid;
/* user ID of owner */
gid_t st_gid;
/* group ID of owner */
off_t st_size;
/* size in bytes, for regular files */
time_t st_atime;
/* time of last access */
time_t st_mtime;
/* time of last modification */
time_t st_ctime;
/* time of last file status change */
blksize_t st_blksize;
/* best I/O block size */
blkcnt_t st_blocks;
/* number of disk blocks allocate */
}

3 判断文件类型

文件类型信息包含在 stat 结构的st_mode 成员中。可以使用下表 1 中的宏来确定文件类型。这些宏的参数都是 stat 结构的st_mode 成员。

表 1: <sys/stat.h> 中的文件类型宏
文件类型
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或 FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字


 下面程序取其命令行参数,然后针对每个命令行参数打印其文件类型。

#include <stdlib.h>
#include
<stdio.h>
#include
<sys/stat.h>
#include
<errno.h>
#include
<string.h>
int
main(
int argc, char *argv[])
{
int i;
struct stat buf;
char *ptr;
for (i=0; i < argc; i++) {
printf(
"%s: ", argv[i]);
if (lstat(argv[i], &buf) < 0) {
printf(
"lstat error: %s\n", strerror(errno));
continue;
}
if (S_ISREG(buf.st_mode)) {
ptr
= "regular";
}
else if (S_ISDIR(buf.st_mode)) {
ptr
= "directory";
}
else if (S_ISCHR(buf.st_mode)) {
ptr
= "character special";
}
else if (S_ISBLK(buf.st_mode)) {
ptr
= "block special";
}
else if (S_ISFIFO(buf.st_mode)) {
ptr
= "fifo";
}
else if (S_ISLNK(buf.st_mode)) {
ptr
= "symbolic link";
}
else if (S_ISSOCK(buf.st_mode)) {
ptr
= "socket";
}
else {
ptr
= "** nuknown mode **";
}
printf(
"%s\n", ptr);
}
exit(
0);
}

编译该程序,生成文件 filetype,然后运行 filetype 文件,

lienhua34:demo$ gcc -o filetype filetype.c
lienhua34:demo$ .
/filetype /etc/passwd /etc /dev/initctl /dev/log /dev/tty
.
/filetype: regular
/etc/passwd: regular
/etc: directory
/dev/initctl: lstat error: No such file or directory
/dev/log: socket
/dev/tty: character special

(done)