Linux 程序设计学习笔记----文件管理实例应用

一、使用ls -l 以排序方式输出目录信息

1.需求以及知识点覆盖

ls -l 命令根据后面的参数将列出某文件即目录下的基本信息。

如果没有具体的目录或者文件,则列出当前目录下所有的非隐藏文件的信息,包括文件类型,文件权限,硬链接个数,拥有者。拥有者所在组,文件大小,文件更新时间等。

such as :

若没有指定的文件,则输出所有目录下的文件信息:

所以,本应用要实现的基本功能和需要的知识点有:

①参数检查。包括参数个数检查,如果有多个需要列出信息的文件及目录,则遍历所有的参数,另外需要读取当前参数是文件还是目录。(stat函数可以读取)

②如果是普通文件,需要构建此文件的链表,然后使用stat()函数读取链表成员文件的属性,并根据stat输出结果进行用户ID到用户名的转化,组id到组名的转换,以及时间的转换(stat函数的时间是linux时间,1970-1-1至此刻的秒数)。

③如果是目录文件,需要一次读取该目录先的文件列表,并按需存储在链表中,本示例中选用简单的插入排序,然后读取该文件的基本信息。

2.流程

主函数流程如下:

①参数检查。参数不能少于两个,如果参数大于两个,列出对应的信息。

②检测参数类型,如果是普通文件且存在,则读取该文件的属性。

③如果是目录文件,循环查找目录下的所有文件,采用及简单的插入排序读取信息,并列出整个链表文件信息。

3.代码实现

具体代码如下,详细过程那个见注释。

/*************************************************************************
> File Name: sort_l.c
> Author: SuooL
> Mail: [email protected]
> Created Time: 2014年07月31日 星期五 15时44分32秒
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<dirent.h>
#include<string.h>
#include<sys/stat.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>

#define NAME_SIZE 256

// 构建的链表节点数据结构
struct fnode
{
	struct fnode *next;     // 下一个成员
	char name[NAME_SIZE];   // 当前成员文件名
};

struct fnode *insert_list(struct fnode *temp,struct fnode *head)
{
	if(head==NULL)	//if linklist is empty,for temp is the first one
	{
		head=temp;
		return head;
	}

	if(strcmp(temp->name,head->name)<0) //temp will be insert before first one
	{
		temp->next=head;
		head=temp;
		return head;
	}

	struct fnode *next=head->next;
	struct fnode *prev=head;
	while(next!=NULL&& strcmp(temp->name,next->name)>0)
	{
		next=next->next;
		prev=prev->next;
	}
	temp->next=next;
	prev->next=temp;
	return head;
}

// 读取文件权限属性函数,根绝参数(lstat函数返回类型st_mode)列出各个文件的权限个类型字符
output_type_perm(mode_t mode)
{
	char  type[7]={'p','c','d','b','-','l','s'};
	int index=((mode>>12) & 0xF)/2;
	printf("%c",type[index]);

	char *perm[8]={"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};//rwx
	printf("%s",perm[mode>>6 &07]);
	printf("%s",perm[mode>>3 &07]);
	printf("%s",perm[mode>>0 &07]);
}

// 列出用户及组
void output_user_group(uid_t uid,gid_t gid)
{
	struct passwd *user;
	user=getpwuid(uid);
	printf("  %s",user->pw_name);

	struct group *group;
	group=getgrgid(gid);
	printf(" %s",group->gr_name);
}

// 列出个文件基本信息函数将各个函数的返回值输出的屏幕
output_mtime(time_t mytime)
{
	char buf[256];
	memset(buf,'\0',256);
	ctime_r(&mytime,buf);
	buf[strlen(buf)-1]='\0';
	//memcpy(buf,ctime(mytime),strlen(ctime(mytime))-1);
	printf("  %s",buf);
}

void output_info(struct fnode *head)
{
	struct fnode *temp=head;
	while(temp!=NULL)
	{
		struct stat mystat;
		if(-1==stat(temp->name,&mystat))
		{
			perror("stat");exit(EXIT_FAILURE);
		}
		output_type_perm(mystat.st_mode);
		printf("  %4d",mystat.st_nlink);
		output_user_group(mystat.st_uid,mystat.st_gid);
		printf(" %8ld",mystat.st_size);
		output_mtime(mystat.st_mtime);
		printf(" %s\n",temp->name);
		temp=temp->next;
	}

}
void free_list(struct fnode *ptr)
{
	struct fnode *temp=ptr;
	struct fnode *link=ptr;
	while(ptr)
	{
		temp=ptr;
		ptr=ptr->next;
		free(temp);
	}
}

// main()函数源码
int main(int argc,char *argv[])
{
	if(argc < 2)
	{
		printf("usage :%s dir_name\n",argv[0]);exit(EXIT_FAILURE);
	}

	int i;
	for(i=1;i<argc;i++)
	{
		struct fnode *linklist=NULL;

		struct stat stat_info;
		if(stat(argv[i],&stat_info)==-1)
		{
			perror("stat");exit(EXIT_FAILURE);
		}

		if (S_ISREG(stat_info.st_mode))		//regular file
		{
			struct fnode *temp=(struct fnode *)malloc(sizeof(struct fnode));
			if(NULL==temp)
			{
				perror("malloc");exit(EXIT_FAILURE);
			}
			temp->next=NULL;
			memset(temp->name,'\0',NAME_SIZE);
			memcpy(temp->name,argv[i],strlen(argv[i]));
			linklist=insert_list(temp,linklist);
			output_info(linklist);//output information of the file
		}
		else if(S_ISDIR(stat_info.st_mode))
		{
			char buf[NAME_SIZE];
			getcwd(buf,128);

			DIR  *dirp=NULL;
			dirp=opendir(argv[i]);
			if(NULL==dirp)
			{
				perror("opendir");exit(EXIT_FAILURE);
			}

			struct dirent *entp=NULL;
			while(entp=readdir(dirp))
			{
				struct fnode *temp=(struct fnode *)malloc(sizeof(struct fnode));
				if(NULL==temp)
				{
					perror("malloc");exit(EXIT_FAILURE);
				}
				temp->next=NULL;
				memset(temp->name,'\0',NAME_SIZE);
				memcpy(temp->name,entp->d_name,strlen(entp->d_name));
				linklist=insert_list(temp,linklist);
			}
			chdir(argv[i]);//change the current dirctory
			close(dirp);
			output_info(linklist);
			chdir(buf);
		}
		free_list(linklist);
	}
	return 1;
}

运行结果:

二、实现tree系统命令

1.问题分析

linux中的tree命令可以实现以树形结构列出某个指定目录下的所有问价以及目录名,如下所示的效果:

我们就要实现这样一个tree命令。基本的流程如下:

(1)系统初始化。构建一个空队列,该队列将实时缓存整个目录(含有子目录)中未输出的文件呢信息。

(2)读取目录下所有的文件信息以及目录信息,按照ASCII码值的大小构建一个新的子排序队列。

(3)将子队列与整个目录的队列合并,采用的方法类似于栈的操作,即将整个子队列加到原来的队列的前面,更新全局队列的信息。

(4)出队列。读取队列的第一个成员的属性。如果是一个文件,直接按信息输出,如果是一个目录,重复上面的(2)(3)(4)步骤。递归循环操作。

2.程序流程图

3.代码

关于递归部分,类似与之前写的递归复制目录文件的应用小程序。

<pre name="code" class="cpp">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>

#define REGU_FILE 1
#define DIR_FILE 2

// 构建栈式结构中每个节点代表一个文件,节点数据结构定义如下:
typedef struct node
{
    struct node *next;   // 下一个节点,构建单链结构
    unsigned int level;  // 当前子目录的深度,用于区分输出时的层次
    char *name;          // 所在的目录下的文件名,不含有上级目录,用于输出名字
    char *fullname;	     // 输出整个路径名,用于读取属性
}filenode;

// 队列数据结构
typedef struct head
{
    struct node *head;   // 队首指针
    struct node *rear;   // 队尾指针
}headnode;

void dir_tree(char *dirname,headnode *link_stack, int level);

int insert_sort(headnode *link_stack, filenode *NEW)
{

    filenode *next = link_stack->head;
    filenode *prev = NULL;
    while(next)
    {
        if (strcmp( NEW->name, next->name ) > 0 )
        {
            prev = next;
            next = next->next;
        }
        else
        break;
    }

    if(link_stack->head == NULL && link_stack->rear == NULL)	//the first one
    {
        link_stack->head = NEW;
        link_stack->rear = NEW;
    }
    else if(prev == NULL && next != NULL)		//insert in front of the queue
    {
        NEW->next = link_stack->head;
        link_stack->head = NEW;
    }
    else if( prev != NULL && next == NULL)		//insert in end of the queue.
    {
        prev->next = NEW;
        link_stack->rear = NEW;
    }
    else
    {
        prev->next = NEW;
        NEW->next = next;
    }
}

headnode *read_dir_to_link_stack(char *dir,int level)
{
    DIR *dirp = NULL;

    if(NULL== (dirp=opendir(dir)))
    {
        perror("opendir");exit(EXIT_FAILURE);
    }	

    headnode *ptr = (headnode *)malloc (sizeof (headnode));
    if(ptr==NULL)
    {
        perror("malloc");exit(EXIT_FAILURE);
    }
    ptr->head = NULL;
    ptr->rear = NULL;	

    struct dirent *entp = NULL;
    while ( NULL != (entp =readdir(dirp)))
    {
        if (strcmp(entp->d_name, "..")==0 || strcmp(entp->d_name, ".")==0)	//ignore ./ ../
        {
            continue;
        }
        else
        {
            filenode *temp = (filenode *)malloc(sizeof(filenode));
            if(temp==NULL)
            {
                perror("malloc");exit(EXIT_FAILURE);
            }
            temp->next = NULL;
            temp->level = level;

            temp->name = (char *)malloc(strlen( entp->d_name) + 1);
            sprintf(temp->name ,"%s\0", entp->d_name);

            temp->fullname = (char *)malloc(strlen(dir)+1+strlen( entp->d_name) + 1);
            sprintf(temp->fullname,"%s/%s\0",dir,entp->d_name);

            insert_sort(ptr,temp);
        }
    }
    closedir(dirp);
    return ptr;
}
/*
type:1, regufile. 2 dir.
*/
// 输出某个文件的信息格式
void out_file_info(filenode *ptr, int type)
{
    int i;
    printf("|");
    for(i = 0;i < ptr->level; i++)
    {
        printf("    ");
    }
    printf("|-- ");
    printf("%s\n",ptr->name);
}

void pop_file_tree(headnode *link_stack)
{
    while(link_stack->head != NULL )        // 遍历所有节点
    {
        struct stat stat_src;
        if (lstat(link_stack->head->fullname, &stat_src) != 0)
        {
            fprintf(stderr, "%s(%d): stat error(%s)!\n", __FILE__, __LINE__, strerror(errno));
        }	

        if(S_ISDIR(stat_src.st_mode))            // 目录,调用dir_tree函数
        {
            filenode *temp = link_stack->head;
            link_stack->head = link_stack->head->next;
            if(link_stack->head == NULL)
            link_stack->rear ==NULL;
            out_file_info(temp,DIR_FILE);
            dir_tree(temp->fullname,link_stack,temp->level);
            free(temp->name);
            free(temp->fullname);
            free(temp);
        }
        else                             // 否则输出文件
        {
            filenode *temp = link_stack->head;
            link_stack->head = link_stack->head->next;
            if(link_stack->head == NULL)
            link_stack->rear ==NULL;

            out_file_info(temp,REGU_FILE);

            free(temp->name);
            free(temp->fullname);
            free(temp);
        }
    }
}

// 输出目录和子目录信息递归函数
void dir_tree(char *dirname,headnode *link_stack, int level)
{
    headnode *ret = NULL;
    // 读取目录信息,返回一个排序队列,队列中每个节点包括子文件的文件名和整个路径
    ret = read_dir_to_link_stack(dirname, level+1);

    // 将原队列与新的返回队列合并,将新的返回队列放到原队列前,类似于栈操作
    if(link_stack->head != NULL && ret->head != NULL)
    {
        ret->rear->next = link_stack->head;
        link_stack->head = ret->head;
    }

    if(link_stack->head == NULL && ret->head != NULL )
    link_stack->head = ret->head;

    if(link_stack->rear == NULL && ret->rear != NULL)
    link_stack->rear = ret->rear;

    free(ret);
    pop_file_tree(link_stack);
}

int main(int argc,char *argv[])
{
    if (argc != 2 )     // 如果没有给定目录
    {
        fprintf(stderr,"pls useage %s dir_name\n",argv[0]);exit(EXIT_FAILURE);
    }

    struct stat stat_src;
    if (lstat(argv[1], &stat_src) != 0)    // 读取文件属性
    {
        fprintf(stderr, "%s(%d): stat error(%s)!\n", __FILE__, __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }	

    if (S_ISREG(stat_src.st_mode))		//regular file,报错
    {
        fprintf(stderr, "%s [error opening dir]\n",argv[1]);exit(EXIT_FAILURE);
    }
    else if(S_ISDIR(stat_src.st_mode))        // 目录文件
    {
        headnode *link_stack = (headnode *)malloc (sizeof (headnode));
        if(link_stack == NULL)
        {
            perror("malloc");exit(EXIT_FAILURE);
        }
        link_stack->head = NULL;        // 初始化全局队列
        link_stack->rear = NULL;

        printf("%s\n",argv[1]);
        dir_tree(argv[1], link_stack,-1);  // 执行函数

        free(link_stack);             // 完毕,回收内存
    }
    else
    	return 1;
}

运行结果:

Next

终端及串口编程

Linux进程管理与程序开发

Linux 程序设计学习笔记----文件管理实例应用

时间: 2024-08-03 10:36:09

Linux 程序设计学习笔记----文件管理实例应用的相关文章

Linux 程序设计学习笔记----终端及串口编程及实例应用

转载请注明出处,http://blog.csdn.net/suool/article/details/38385355. 部分内容类源于网络. 终端属性详解及设置 属性 为了控制终端正常工作,终端的属性包括输入属性.输出属性.控制属性.本地属性.线路规程属性以及控制字符. 其在系统源代码的termios.h中定义(具体的说明文档http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html),其结构体成员主要是 Thetermios

Linux 程序设计学习笔记----终端及串口编程基础之概念详解

转载请注明出处,谢谢! linux下的终端及串口的相关概念有: tty,控制台,虚拟终端,串口,console(控制台终端)详解 部分内容整理于网络. 终端/控制台 终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念. 1.终端 一台主机,连很多终端,终端为主机提供了人机接口,每个人都通过终端使用主机的资源. 终端有字符哑终端和图形终端两种. 控制台是另一种人机接口, 不通过终端与主机相连, 而是通过显示卡-显示器和键盘接口分别与主机相连, 这是人控制主机的第一人机接口.

Linux 程序设计学习笔记----Linux下文件类型和属性管理

转载请注明出处:http://blog.csdn.net/suool/article/details/38318225 部分内容整理自网络,在此感谢各位大神. Linux文件类型和权限 数据表示 文件属性存储结构体Inode的成员变量i_mode存储着该文件的文件类型和权限信息.该变量为short int类型. 这个16位变量的各个位功能划分为: 第0-8位为权限位,为别对应拥有者(user),同组其他用户(group)和其他用户(other)的读R写W和执行X权限. 第9-11位是权限修饰位,

Linux 程序设计学习笔记----ANSI C 文件I/O管理

转载请注明出处:http://blog.csdn.net/suool/article/details/38129201 问题引入 文件的种类 根据数据存储的方式不同,可以将文件分为文本文件和二进制文件.具体的区别和关系如下: 文本文件与二进制文件在计算机文件系统中的物理存储都是二进制的,也就是在物理存储方面没有区别都是01码,这个没有异议,他们的区别主要在逻辑存储上,也就是编码上. 文本文件格式存储时是将值作为字符然后存入其字符编码的二进制,文本文件用'字符'作为单位来表示和存储数据,比如对于1

Linux程序设计学习笔记----System V进程通信之消息队列

一个或多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通讯机制通常使用在客户/服务器模型中,客户向服务器发送请求消息,服务器读取消息并执行相应请求.在许多微内核结构的操作系统中,内核和各组件之间的基本通讯方式就是消息队列.例如,在 MINIX 操作系统中,内核.I/O 任务.服务器进程和用户进程之间就是通过消息队列实现通讯的. Linux中的消息可以被描述成在内核地址空间的一个内部链表,每一个消息队列由一个IPC的标识号唯一的标识.Linux 为系统中所有的消息队

Linux程序设计学习笔记----网络通信编程API及其示例应用

转载请注明出处, http://blog.csdn.net/suool/article/details/38702855. BSD Socket 网络通信编程 BSD TCP 通信编程流程 图为面向连接的Socket通信的双方执行函数流程.使用TCP协议的通信双方实现数据通信的基本流程如下 建立连接的步骤 1.首先服务器端需要以下工作: (1)调用socket()函数,建立Socket对象,指定通信协议. (2)调用bind()函数,将创建的Socket对象与当前主机的某一个IP地址和TCP端口

Linux 程序设计学习笔记----进程管理与程序开发(下)

转载请注明出处:http://blog.csdn.net/suool/article/details/38419983,谢谢! 进程管理及其控制 创建进程 fork()函数 函数说明具体参见:http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html 返回值:Upon successful completion, fork() shall return 0 to the child process and shall re

Linux 程序设计学习笔记----POSIX 文件及目录管理

转载请注明:http://blog.csdn.net/suool/article/details/38141047 问题引入 文件流和文件描述符的区别 上节讲到ANSI C 库函数的实现在用户态,流的相应资源也在用户空间,但无论如何实现最终都需要通过内核实现对文件的读写控制.因此fopen函数必然调用了对OS的系统调用.这一调用在LINUX下即为open, close, read, write等函数.这些都遵循POSIX标准. so,在linux系统中是如何通过POSIX标准实现对文件的操作和目

Linux程序设计学习笔记----System V进程间通信(信号量)

关于System V Unix System V,是Unix操作系统众多版本中的一支.它最初由AT&T开发,在1983年第一次发布,因此也被称为AT&T System V.一共发行了4个System V的主要版本:版本1.2.3和4.System V Release 4,或者称为SVR4,是最成功的版本,成为一些UNIX共同特性的源头,例如"SysV 初始化脚本"(/etc/init.d),用来控制系统启动和关闭,System V Interface Definitio