操作系统实践 job4

目录

job4/myls.c

前置知识

实现思路

结果展示

job4/mytree.c

前置知识

实现思路

结果展示


job4/myls.c

  • myls.c的功能与系统ls程序相同
  • opendir readdir closedir
  • 在命令行中输入 man opendir 获取帮助
  • 列出指定目录下的文件,例子如下:
    $ ./myls job4/test
    a
    b
    c
    
  • 列出当前目录下的文件,例子如下:
    $ cd job4/test 
    $ ./myls
    a
    b
    c

前置知识

引:先了解一下数据结构!


DIR *dp;  // 指向目录
struct dirent *dirp; // 指向目录中的对象

//DIR结构
struct __dirstream
{
void *__fd; /* struct hurd_fd pointer for descriptor.   */
char *__data; /* Directory block.   */
int __entry_data; /* Entry number __data corresponds to.   */
char *__ptr; /* Current pointer into the block.   */
int __entry_ptr; /* Entry number __ptr corresponds to.   */
size_t __allocation; /* Space allocated for the block.   */
size_t __size; /* Total valid data in the block.   */
__libc_lock_define (, __lock) /* Mutex lock for this structure.   */
};

typedef struct __dirstream DIR;

//dirent结构
struct dirent
{
   long d_ino; /* inode number 索引节点号 */
   off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
   unsigned short d_reclen; /* length of this d_name 文件名长 */
   unsigned char d_type; /* the type of d_name 文件类型 */
   char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
}

然后了解一下几个关键函数:

1.  opendir

头文件:#include <dirent.h>
定义函数:DIR * opendir(const char * name);
函数说明:opendir()用来打开参数name 指定的目录, 并返回DIR*形态的目录流, 和open()类似, 接下来对目录的读取和搜索都要使用此返回值.
返回值:成功则返回DIR* 型态的目录流, 打开失败则返回NULL.

2. readdir

头文件:#include <dirent.h>
定义函数:struct dirent * readdir(DIR * dir);
函数说明:readdir()返回参数dir 目录流的下个目录进入点

3. closedir

关闭目录啦

实现思路

提取输入字符串,如果为空,则默认当前目录,使用getcwd()获取当前目录路径。

如果不为空,则判断该路径是否存在,若存在就打开该目录,并依次读取目录下的文件名,.与..省略不计。

#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
	DIR *dp;//指向目录
	struct dirent *sdp;//指向目录下对象
	if(argv[1]==NULL)//判断参数是否为空
	{
		char str[80];
		getcwd(str,sizeof(str));//直接获取当前地址
		dp=opendir(str);//打开目录,指向第一个对象
	}
	else if((dp=opendir(argv[1]))==NULL)//打开目录,并判断目录是否存在
	{
		perror("opendir error\n");
		exit(1);
	}
	while((sdp=readdir(dp))!=NULL)//不断读取目录下的内容,指向下一个对象直到为空
	{
		if(!strcmp(sdp->d_name,".")||!strcmp(sdp->d_name,".."))continue;
		printf("%s\t",sdp->d_name);
	}
	printf("\n");
    closedir(dp);
	return 0;
}

结果展示

job4/mytree.c

  • mytree.c的功能与系统tree程序相同
  • 使用空格作为缩进,表示层次
    $ ./mytree job4/test
    test
      a
      b
        x
        y
        z
      c

参考了这位大哥:

9.自己实现linux中的tree - 喵小喵~ - 博客园

前置知识

stat结构体:
struct stat {
    dev_t         st_dev;       //文件的设备编号
    ino_t          st_ino;       //节点
    mode_t      st_mode;      //文件的类型和存取的权限
    nlink_t        st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t          st_uid;       //用户ID
    gid_t          st_gid;       //组ID
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
    off_t          st_size;      //文件字节数(文件大小)
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;    //块数
    time_t        st_atime;     //最后一次访问时间
    time_t        st_mtime;     //最后一次修改时间
    time_t        st_ctime;     //最后一次改变时间(指属性)
};

主要用到st_mode,表示文件类型:

S_IXUSR    00100      文件所有者具可执行权限

S_ISDIR(st_mode)        是否为目录

sprintf函数:

C 库函数 int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。

e.g.

 sprintf(str, "Pi 的值 = %f", M_PI);
 //str="Pi 的值 = 3.141593"

实现思路

首先输入路径,缺省即获取当前路径。

mytree函数类似于深搜:

  • 打开目录,获取文件列表,依次打印文件名
  • 对文件名进行判断,如果是目录类型继续深搜,深度+1,并格式化输出文件名;
  • deep深度参数用于打印缩进。
  • dirc,fc变量用于统计文件数和目录数。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<stdlib.h>
int dirc=0,fc=0;
void mytree(char path[],int deep)
{
	DIR *dp;//directory point
	struct dirent *sdp;//file point
	char sonpath[1024];
	struct stat f_info;
	//struct stat f_info;//file infomation
	if((dp=opendir(path))==NULL)
	{
		perror("opendir error");
		exit(1);
	}
	//open current dictionary and check the error
	while((sdp=readdir(dp))!=NULL)
	{
		stat(sdp->d_name,&f_info);
		if(!strcmp(sdp->d_name,".")||!strcmp(sdp->d_name,".."))continue;
		for(int i=0;i!=deep;i++)printf("|    ");
		if(sdp->d_type== DT_DIR)
		{
			//blue
			dirc++;
			printf("|----\033[0;32;34m%s\033[0m\n",sdp->d_name);
			sprintf(sonpath,"%s/%s",path,sdp->d_name);
			mytree(sonpath,deep+1);	
			//same as dfs
		}	
		else if(f_info.st_mode&00100)//exe filr
		{
			fc++;
			//green
			printf("|----\033[1;32m%s\033[0m\n",sdp->d_name);
		}
		else 
		{
			fc++;
			printf("|----%s\n",sdp->d_name);
		}
	}
	closedir(dp);
}
int main(int argc,char* argv[])
{
	if(argv[1]==NULL)
	{
		char str[1024];
		getcwd(str,sizeof(str));
		printf(".\n");
		mytree(str,0);
	}
	else
	{
		struct stat file;
		stat(argv[1],&file);
		if(S_ISDIR(file.st_mode))printf("|----\033[0;32;34m%s\033[0m\n",argv[1]);
		else printf("%s\n",argv[1]);
		mytree(argv[1],0);
	}
	if(dirc==1)printf("1 directory, ");
	else if(dirc>=2)printf("%d directories, ",dirc);
	if(fc==1)printf("1 file.\n");
	else if(fc>=2)printf("%d files.\n",fc);
	return 0;
}

		

结果展示

系统的:

我的:

 还原度还算高啦!很严谨的!甚至区分了单复数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值