分享
 
 
 

Unix环境高级程序设计入门----文件系统的相关编程(下)

王朝system·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

Unix环境高级程序设计入门

----文件系统的相关编程(下)

在上文中,我们已经熟悉了文件描述符的相关知识,这里再介绍一下文件描述符的拷贝。Unix系统除了允许属于两个独立进程的不同文件描述符指向同一文件表项外,还允许同一进程的不同文件描述符指向同一个文件表项。这一特点被称为文件描述符的拷贝,可以通过使用dup函数或dup2函数来实现。它们的定义是:

#include <unistd.h>

int dup(int fd); //成功时返回新的文件描述符,失败则返回-1

int dup2(int fd1, int fd2); //成功时返回新的文件描述符,失败则返回-1

由dup函数返回的文件描述符一定是当前可用文件描述符中的最小数值,而dup2函数则可以利用参数fd2指定欲返回的文件描述符的数值。如果fd2已经打开,则先将其关闭;但如果fd2等于fd1,则dup2返回fd2,而不关闭它。使用dup函数返回的新文件描述符与参数fd共享同一个文件表项,而dup2函数返回的新文件描述符与fd1共享同一个文件表项。

[程序5]

#include <iostream>

#include <sys/types.h>

#include <unistd.h>

#include <string>

using namespace std;

int main()

{

int fd1, fd2;

string msg = "please enter a string: ";

write(1,msg.c_str(),msg.size()); //把msg的内容输出到屏幕上,c_str()函数用于string类型的转换

fd1 = dup(0); //fd1对应于cin

char* buf = new char[250];

memset(buf,0x00,250);

read(fd1,buf,250);

fd2 = dup2(1,7); //fd2=7,对应于cout

write(fd2,buf,strlen(buf));

delete [] buf;

return 0;

}

当此程序开始执行时,假定下一个可用的描述符是3,则fd1=3,且与文件描述符0共享同一文件表项。程序将提示用户输入一字符串,当从键盘输入一串字符后会在屏幕上打印出来。有关于描述符更多的应用,将在后续有关文章中进行介绍。

下面再来介绍一个新知识点,那就是如何在程序中获得文件的属性。这里需要用到三个函数,它们的定义是:

#include <sys/types.h>

#include <sys/stat.h>

int stat(const char* pathname, struct stat* buf); //成功则返回0,失败返回-1

int fstat(int fd, struct stat* buf); //成功则返回0,失败返回-1

int lstat(const char* pathname, struct stat* buf); //成功则返回0,失败返回-1

stat()函数接收一个文件名,返回该文件的stat结构。fstat()接收一个已打开的文件描述符,返回该文件的stat结构。lstat()与stat()类似,但对于符号链接,它返回该符号链接的stat结构,而不是该符号链接所引用文件的stat结构。stat结构是一包含了文件所有属性信息的结构,它的定义如下:

struct stat{

mode_t st_mode; //file type & mode

ino_t st_ino; //i-node number

dev_t st_dev; //device number

dev_t st_rdev; //device number for special 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

long st_blksize;//best I/O block size

long st_blocks; //number of 512 bytes blocks allocated

};

stat结构中最常用到的属性是st_mode(文件的类型及文件的访问权限)、st_nlink(硬链接数,表示有几个链接到该文件上)、st_uid、st_gid、st_size(以字节为单位的文件长度,只对普通文件、目录文件和符号连接有意义)、st_atime、st_mtime、st_ctime。

我们曾一再提到Unix系统中一切皆可视为文件,不过细而化之的话又可以分为多种类型,那么在程序中如何去对文件类型进行判别呢?这就需要用到下表中所示的一些宏:

作用

S_ISREG()

测试是否为普通文件

S_ISDIR()

测试是否为目录文件

S_ISCHR()

测试是否为字符特殊文件

S_ISBLK()

测试是否为块特殊文件

S_ISFIFO()

测试是否为FIFO文件

S_ISLNK()

测试是否为链接文件

S_ISSOCK()

测试是否为socket文件

S_ISUID()

测试是否设置了“设置-用户-ID”位

S_ISGID()

测试是否设置了“设置-组-ID”位

[程序6]

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

int main(int argc, char * argv[])

{

int i;

struct stat buf;

char *ptr;

for(i=1; i< argc; i++)

{

printf("%s: ", argv[i]);

if(lstat(argv[i],&buf)<0)

{

printf("lstat error.");

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 = "char special";

else if(S_ISBLK(buf.st_mode)) ptr = "block special";

else if(S_ISFIFO(buf.st_mode)) ptr = "fifo";

else ptr = "Others";

printf(" %s\n",ptr );

}

return 0;

}

编译程序后,我们先来使用命令mkfifo myfifo.pipe建一个管道文件,然后运行:

filetype myfifo.pipe . /etc/passwd

屏幕会显示:

myfifo.pipe: fifo

.: directory

/etc/passwd: regular

此外,st_mode属性还包含了可用于对文件的属主及权限进行判断的宏,如下表所示:

意义

S_IRUSR

所有者-读

S_IWUSR

所有者-写

S_IXUSR

所有者-执行

S_IRGRP

组-读

S_IWGRP

组-写

S_IXGRP

组-执行

S_IROTH

其他-读

S_IWOTH

其他-写

S_IXOTH

其他-执行

[程序7]

#include <iostream>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

using namespace std;

int main()

{

cout << " enter a file name: ";

char name[255];

cin >> name;

struct stat buf;

if(lstat(name,&buf)<0)

{

cout << " file not existing. " << endl;

return -1;

}

if(buf.st_mode & S_IRUSR) cout << " user can read|";

if(buf.st_mode & S_IWUSR) cout << " user can write|";

if(buf.st_mode & S_IXUSR) cout << " user can execute|";

if(buf.st_mode & S_IRGRP) cout << " group can read|";

if(buf.st_mode & S_IWGRP) cout << " group can write|";

if(buf.st_mode & S_IXGRP) cout << " group can execute|";

if(buf.st_mode & S_IROTH) cout << " other can read|";

if(buf.st_mode & S_IWOTH) cout << " other can write|";

if(buf.st_mode & S_IXOTH) cout << " ohter can execute|";

cout << endl;

return 0;

}

如果是想判断某用户对某一文件的访问权限,则可调用access()函数,它的定义是:

access(const char* path, int amode)

其中,amode对应的值有R_OK(可读)、W_OK(可写)、X_OK(可执行)、F_OK(文件存在)。

三、上下文知识点综合

笔者在参考一些资料的基础上,准备通过编写一个程序模拟“ls -l”命令的功能,来让大家回顾一下上面所介绍的各个知识点。

先来谈一下实现“ls -l”命令的思路:

我们知道使用ls –l命令,可以长列表显示目录的内容,即列出文件的类型、访问权限、拥有者、文件大小、修改时间及名称等详细信息。在程序中,首先使用opendir、readdir函数获得文件及目录名,然后再通过相应的方法来分别获得这些文件或目录的类型、权限、大小等详细信息。

[程序8]

#include <iostream>

using namespace std;

#include <sys/types.h>

#include <sys/stat.h>

#include <dirent.h>

#include <time.h>

#include <pwd.h>

#include <grp.h>

//获得文件的类型,返回值可能是(-, d, c, b, p, l, s, ?)

char fileType(const struct stat & st);

//得到权限的表示方式,r表示可读,w表示可写,x表示可执行

void priv(const struct stat & st, char *privs, const int belong[3]);

//获得所有者的访问权限

void ownerPriv(const struct stat & st, char *privs);

//获得组的访问权限

void groupPriv(const struct stat & st, char *privs);

//获得其他人的访问权限

void otherPriv(const struct stat & st, char *privs);

//将默认的权限表示成"---"

void setDefault(char *privs);

//显示文件的名字、最后修改时间等属性

void trival(const struct stat & st, const char * name);

//显示权限

void dispPriv( void (*f)(const struct stat &, char *), const struct stat & st, char * privs);

int main(int argc, char* argv[])

{

DIR *dp;

struct dirent *dirp;

if (argc == 1)

dp = opendir( "." );

else

dp = opendir( argv[1] );

if(dp == NULL){

struct stat st;

if(lstat(argv[1], &st) < 0){

cout << "No such file or directory" << endl;

exit(1);

}else{

char privs[4];

cout << fileType(st);

dispPriv(ownerPriv, st, privs);

dispPriv(groupPriv, st, privs);

dispPriv(otherPriv, st, privs);

trival(st, argv[1]);

exit(0);

}

}

while ( (dirp = readdir(dp)) != NULL) {

struct stat st;

char fn[200];

if (argc == 1) strcpy(fn, dirp->d_name);

else sprintf(fn, "%s//%s", argv[1], dirp->d_name);

if( lstat(fn, &st) < 0) {

cout << "error" << endl;

continue;

}

cout << fileType(st);

char privs[4];

dispPriv(ownerPriv, st, privs);

dispPriv(groupPriv, st, privs);

dispPriv(otherPriv, st, privs);

trival(st, dirp->d_name);

}

closedir(dp); exit(0);

}

void setDefault(char * privs){

memset(privs, 0, sizeof(privs));

strcpy(privs, "---");

}

char fileType(const struct stat & st){

char type = '?';

if S_ISREG(st.st_mode) { type = '-';

}else if S_ISDIR(st.st_mode) { type = 'd';

}else if S_ISCHR(st.st_mode) { type = 'c';

}else if S_ISBLK(st.st_mode) { type = 'b';

}else if S_ISFIFO(st.st_mode) { type = 'p';

}else if S_ISLNK(st.st_mode) { type = 'l';

}else if S_ISSOCK(st.st_mode) { type = 's';

}

return type;

}

void ownerPriv(const struct stat & st, char * privs){

const int OWNER[3] = {S_IRUSR, S_IWUSR, S_IXUSR};

priv(st, privs, OWNER);

}

void groupPriv(const struct stat & st, char * privs){

const int GROUP[3] = {S_IRGRP, S_IWGRP, S_IXGRP};

priv(st, privs, GROUP);

}

void otherPriv(const struct stat & st, char * privs){

const int OTHER[3] = {S_IROTH, S_IWOTH, S_IXOTH};

priv(st, privs, OTHER);

}

void priv(const struct stat & st, char * privs, const int belong[3]){

if (st.st_mode & belong[0]) *privs = 'r';

++privs;

if (st.st_mode & belong[1]) *privs = 'w';

++privs;

if (st.st_mode & belong[2]) *privs = 'x';

}

void dispPriv( void (*f)(const struct stat &, char *), const struct stat & st, char * privs)

{

setDefault(privs);

f(st, privs);

cout << privs;

}

void trival(const struct stat & st, const char * name){

cout.width(8);

cout << " " << st.st_nlink;

struct passwd* pwd;

struct group* grp;

pwd = getpwuid(st.st_uid);

grp = getgrgid(st.st_gid);

cout << " " << pwd->pw_name << "\t" << grp->gr_name;

cout.width(16);

cout << st.st_size;

char * timeStr = ctime(&st.st_mtime);

timeStr[strlen(timeStr) - 1] = 0;

cout << " " << timeStr;

cout << " " << name << endl;

}

Unix环境中的文件系统相关编程知识暂时介绍至此,后有时间再整理其他方面的学习体会,感谢师友们的关注支持与帮助指正。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有