134 Linux 系统编程11 ,readlink命令,文件目录rwx权限差异,目录操作函数opendir ,closedir ,readdir,注意这里的目录也有可能是文件

本文介绍了Linux系统编程中的几个关键概念,如使用`readlink`查看软链接指向的文件,通过`getcwd`和`chdir`操作工作目录,以及处理文件权限、目录结构、递归遍历目录统计普通文件数量。还涵盖了`opendir`,`closedir`,和`readdir`函数的使用,以及如何获取和展示文件的基本信息。

一  readlink 命令

前面知道,如果a.soft是一个软链接,我们使用 cat a.soft,会直接查看这个软链接指向的文件

那么我们就是想看这个软链接是啥,可以使用 readlink a.soft

二 获取工作目录 getcwd函数

获取进程当前工作目录 (卷3,标库函数)

size 为buf 的大小。

char *getcwd(char *buf, size_t size); 成功:buf中保存当前进程工作目录位置。失败返回NULL。

成功则 将buf中的数据 作为返回值返回;也就是说,在成功的情况下,返回值和buf中的值是一样的。

失败,则返回 NULL,一般当size 不够大,放不下的时候,就会返回null

三 改变当前进程的工作目录

改变当前进程的工作目录

int chdir(const char *path); 成功:0;失败:-1设置errno为相应值

int main() {
	char nowpath[128];
	getcwd(nowpath,sizeof(nowpath));
	cout << "nowpath = " <<nowpath <<  endl;

	int ret  = chdir("/home/hunandede/projects/linuxcpp/aaa");// aaa 目录是真实存在的 ret =0
	//int ret = chdir("/home/hunandede/projects/linuxcpp/bbb");//bbb目录不存在, ret=-1
	//另一个问题是 chdir虽然成功了,但是意义在哪里,这个当前文件肯定是指的 可执行文件的路径了,改变目录也不会将 执行文件 拷贝到 aaa目录

	cout << "ret = " << ret << endl;

	getcwd(nowpath, sizeof(nowpath));
	cout << "nowpath = " << nowpath << endl;


	return 0;
}

四。文件,目录权限

注意:目录文件也是“文件”。其文件内容是该目录下所有子文件的目录项dentry。 可以尝试用vim打开一个目录。

文件 和 目录 的 RWX的权限 ,对应的操作也不同

r

w

x

文件

文件的内容可以被查看

内容可以被修改

可以运行产生一个进程

cat、more、less…

vi、> …

./文件名

目录

目录可以被浏览

创建、删除、修改文件

可以被打开、进入

ls、tree…

mv、touch、mkdir…

cd

目录设置黏住位:若有w权限,创建不变,删除、修改只能由root、目录所有者、文件所有者操作。

opendir函数

根据传入的目录名打开一个目录 (库函数) DIR * 类似于 FILE *

DIR *opendir(const char *name);   成功返回指向该目录结构体指针,失败返回NULL

    参数支持相对路径、绝对路径两种方式:例如:打开当前目录:① getcwd() , opendir() ② opendir(".");

closedir函数

关闭打开的目录

int closedir(DIR *dirp); 成功:0;失败:-1设置errno为相应值

readdir函数

读取目录 (库函数)

struct dirent *readdir(DIR *dirp);  成功返回目录项结构体指针;失败返回NULL设置errno为相应值

需注意返回值,读取数据结束时也返回NULL值,所以应借助errno进一步加以区分。

struct 结构体:

           struct dirent {

               ino_t          d_ino;      inode编号

               off_t          d_off;       

               unsigned short  d_reclen;    文件名有效长度

               unsigned char   d_type;     类型(vim打开看到的类似@*/等)

               char          d_name[256];文件名

           };

其成员变量重点记忆两个:d_ino、d_name。实际应用中只使用到d_name。

练习1:实现简单的ls功能。 【imp_ls.c】

练习2:实现ls不打印隐藏文件。每5个文件换一个行显示。 【imp_ls2.c】

拓展1:实现ls -a -l 功能。

//1.得到 最前面的那个d, 使用 filetype表示
void getfiletype(__mode_t & smode,char * filetype) {
	switch (smode & S_IFMT) {
	case S_IFBLK:  
		//printf("block device\n");
		strcpy(filetype,"b\0");
		break;
	case S_IFCHR:  
		//printf("character device\n");
		strcpy(filetype, "c\0");
		//return "c";
		break;
	case S_IFDIR:  
		//printf("directory\n");
		//return "d";
		strcpy(filetype, "d\0");
		break;
	case S_IFIFO:  
		//printf("FIFO/pipe\n");
		strcpy(filetype, "p\0");
		//return "p";
		break;
	case S_IFLNK:  
		//printf("symlink\n");
		//return "l";
		strcpy(filetype, "l\0");
		break;
	case S_IFREG:  
		//printf("regular file\n");
		//return "-";
		strcpy(filetype, "-\0");
		break;
	case S_IFSOCK: 
		//printf("socket\n");
		//return "s";
		strcpy(filetype, "s\0");
		break;
	default:       
		printf("unknown\n");
		strcpy(filetype, "u\0");
		break;
	}

}

//2.得到权限 rwxrwxr-x 
void getfilepermissions(__mode_t & smode, char * filepermissions) {

		//S_IRWXU     00700   owner has read, write, and execute permission
		//S_IRUSR     00400   owner has read permission
		//S_IWUSR     00200   owner has write permission
		//S_IXUSR     00100   owner has execute permission

		//S_IRWXG     00070   group has read, write, and execute permission
		//S_IRGRP     00040   group has read permission
		//S_IWGRP     00020   group has write permission
		//S_IXGRP     00010   group has execute permission

		//S_IRWXO     00007   others(not in group) have read, write, and
		//execute permission
		//S_IROTH     00004   others have read permission
		//S_IWOTH     00002   others have write permission
		//S_IXOTH     00001   others have execute permission

	if (smode & S_IRUSR)//-----为真,表示可读
	{
		strcpy(filepermissions, "r\0");
		//filepermission = filepermission + "r";
	}
	else {
		//filepermission = filepermission + "-";
		strcpy(filepermissions, "-\0");
	}
	if (smode & S_IWUSR)//-----为真,表示可写
	{
		strcat(filepermissions,"w\0");
		//filepermissions = filepermission + "w";
	}
	else {
		//filepermissions = filepermission + "-";
		strcat(filepermissions, "-\0");
	}
			
	if (smode & S_IXUSR)//-----为真,表示可执行
	{
		//filepermission = filepermission + "x";
		strcat(filepermissions, "x\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}

	//Group 
			//S_IRGRP     00040   group has read permission
		//S_IWGRP     00020   group has write permission
		//S_IXGRP     00010   group has execute permission
	if (smode & S_IRGRP)//-----为真,表示可读
	{
		//filepermission = filepermission + "r";
		strcat(filepermissions, "r\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}
	if (smode & S_IWGRP)//-----为真,表示可写
	{
		//filepermission = filepermission + "w";
		strcat(filepermissions, "w\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}

	if (smode & S_IXGRP)//-----为真,表示可执行
	{
		//filepermission = filepermission + "x";
		strcat(filepermissions, "x\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}

	//other
			//S_IROTH     00004   others have read permission
		//S_IWOTH     00002   others have write permission
		//S_IXOTH     00001   others have execute permission

	if (smode & S_IROTH)//-----为真,表示可读
	{
		//filepermission = filepermission + "r";
		strcat(filepermissions, "r\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}
	if (smode & S_IWOTH)//-----为真,表示可写
	{
		//filepermission = filepermission + "w";
		strcat(filepermissions, "w\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}

	if (smode & S_IXOTH)//-----为真,表示可执行
	{
		//filepermission = filepermission + "x";
		strcat(filepermissions, "x\0");
	}
	else {
		//filepermission = filepermission + "-";
		strcat(filepermissions, "-\0");
	}
}



int fileinfo(const char * filepathname,const char *filename, char *allstr) {
	int ret = 0;
	struct stat sta ;
	ret = lstat(filepathname,&sta);
	if (ret < 0 ) {
		cout << "stat filepathname error " << filepathname <<  endl;
		perror(" stat filename error");
		return ret;
	}
	//这里得到了文件的属性,得到2 个点,1是文件的类型,2是得到文件的权限,就能弄出来这个了 drwxrwxr-x  
	//drwxrwxr-x  4 hunandede hunandede 4096 2月  21 15:16 .

	//1.得到 最前面的那个d, 使用 filetype表示
	__mode_t smode = sta.st_mode;
	char filetype[2] = { 0 };
	getfiletype(smode, filetype);

	//2.得到权限 rwxrwxr-x 
	char filepermissions[10] = { 0 };
	getfilepermissions(smode,filepermissions);


	//3. 得到user名
	__uid_t userid = sta.st_uid; //__uid_t本质上是 unsigned int

	//4. 得到组名
	__gid_t groupid = sta.st_gid; //__gid_t 本质上是 unsigned int


	//5. 得到文件大小
	__off_t filesize = sta.st_size; // long int

	//6.得到时间
	ctime(&(sta.st_atime));

	//7.得到文件名,已经设置为第二个参数了
	
	//8 组合
	strcpy(allstr,filetype);
	strcat(allstr, filepermissions);
	strcat(allstr, "  ");

	char useridchar[64] = { 0 };
	sprintf(useridchar, "%u", userid);
	strcat(allstr, useridchar);
	strcat(allstr, "  ");


	char groupidchar[64] = { 0 };
	sprintf(groupidchar, "%u", groupid);
	strcat(allstr, groupidchar);
	strcat(allstr, "  ");
	 
	//文件大小
	filesize = filesize / 8;  //filesize 的本质是 long int
	char filesizestr[256] = { 0 };
	sprintf(filesizestr, "%lu", filesize);
	strcat(allstr, "  ");

	//名字
	strcat(allstr, filename);
	strcat(allstr, "  ");

	//时间
	strcat(allstr, ctime(&(sta.st_atime)));//ctime()本身返回的字符串,看起来最后会有一个\n
	//这里的问题是 ctime 本身有一个\n,如果按照ls -la 的命名,时间是在 名字 之前的,也就是说,名字会在下一行才能显示


	//printf("\n");
	return 0;
}

int main() {
	int ret = 0;
	char dirpath[512] = { 0 };
	strcat(dirpath,"/home/hunandede/");
	DIR * pd = opendir(dirpath);
	if (pd == NULL) {//open 失败
		perror("opendir error");
		ret = -1;
		return ret;
	}
	dirent * spd = NULL;

	int num = 0;
	while (true) {
		int temperrno = errno;
		//cout << "before temperrno = " << temperrno << endl;
		spd = readdir(pd);
		if (spd != NULL) {

			//判断是得到的文件的,那么就要从这里得到数据,
			
			//mtk81234 得到文件的整体的名字
			memset(dirpath, 0,512);
			//dirpath[512] = { 0 };
			strcat(dirpath, "/home/hunandede/");
			//cout << "aaa = " << dirpath << endl;
			//cout << "bbb = " << spd->d_name << endl;
			char* filepathname = strcat(dirpath, spd->d_name);
			//cout << "ccc = " << filepathname << endl;
			char allstr[512] = { 0 };
			fileinfo(filepathname, spd->d_name, allstr);
			cout << allstr << endl;
		}
		else {
			//出错 和 读到目录的最后,都会是NULL,需要通过 errno区分
			//cout << "after errno = " << errno << endl;
			if (temperrno != errno) {
				//当出错的时候 errno 变化,和之前记录的temperrno 不一样,因此用这个判断是否有问题
				//perror("readdir error  errno because ");
				ret = errno;
				return ret;
			}
			else {
				//cout << "readdir end " << endl;
				break;
			}
		}
	}

	ret = closedir(pd);
	if (ret == -1) {//close 失败
		perror("opendir error");
		ret = -1;
		return ret;
	}
	cout << endl;
	cout << "duandian" << endl;
}

拓展2:统计目录及其子目录中的普通文件的个数

//拓展2:统计目录及其子目录中的普通文件的个数

bool isfolderfiletype(__mode_t  st_mode) {
	//cout << "st_mode = " << st_mode << endl;
	if ((st_mode & S_IFMT) == S_IFDIR) { //注意这里, & 和 ==的优先级问题,==的优先级要比 & 这个高,因此要用()弄起来
		return true;
	}
	else {
		return false;
	}
}


//使用递归来实现
int filenumber(char * filepathname, int &num) {

	struct stat sta;
	//1 打开目录文件
	DIR *dir = opendir(filepathname);
	dirent *pdirent = NULL;
	int ret = 0;
	while (true) {
		//2 读取目录文件
		pdirent = readdir(dir);

		int temperrno = errno;
		if (pdirent == NULL) {
			//出错 和 读到目录的最后,都会是NULL,需要通过 errno区分
		//cout << "after errno = " << errno << endl;
			if (temperrno != errno) {
				//当出错的时候 errno 变化,和之前记录的temperrno 不一样,因此用这个判断是否有问题
				//perror("readdir error  errno because ");
				ret = errno;
				return ret;
			}
			else {
				//cout << "readdir end " << endl;
				return ret;
			}
		}
		else {
			//3.当读到目录的文件时候,将这个文件的全路径使用filerealpathname记录
			char filerealpathname[256] = { 0 };
			strcat(filerealpathname, filepathname);
			strcat(filerealpathname, "/");
			strcat(filerealpathname, pdirent->d_name);
			//4.再得到这个文件的属性,
			lstat(filerealpathname, &sta);//获取文件属性
			//4.1如果是. 和 ..,我们不显示,注意的是:.和..是文件夹。最后,要continue,让while循环继续。
			if (strcmp(".", pdirent->d_name) == 0 || strcmp("..", pdirent->d_name) == 0) {
				//隐藏 .  和 ..文件,注意这两个还都是文件夹。
				//cout << "childfullnameaaa = " << filerealpathname << endl;
				//cout << "" << endl;
				//num++;
				continue;
			//4.2如果不是.和.. 根据这个文件的属性判断是否是folder,如果是folder,则要再将当前文件塞入该方法,执行
			}else if (isfolderfiletype(sta.st_mode)) {
				//cout << "childfullname = " << filerealpathname << endl;
				filenumber(filerealpathname, num);
			}
			//4.3 如果不是点 和点点,也不是 folder,则说明是文件,直接打印,计数num++;
			else {
				cout << "childfullnameaaa = " << filerealpathname << endl;
				num++;
				continue;
			}

		}
	}


	closedir(dir);
}

int main() {
	int num = 0;
	filenumber("/home/hunandede/projects/linuxcpp",num);
	cout << "num = " << num << endl;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值