Linux系统编程学习笔记_003_文件系统

文件存储

inode

本质是结构体,存储文件的属性信息如:权限、类型、大小、时间、用户、盘块位置等。也叫做文件属性管理结构,大多数inode存储在磁盘上,少量常用、近期使用的inode会被缓存到内存中。

dentry

目录项,本质是结构体,有两个重要的成员变量:1.文件名 2.inode 。文件内容(data)保存在磁盘盘块中。

文件操作

stat函数

#include <sys/stat.h>

#include <unistd.h>

原型:int stat(const char *pathname, struct stat *buf);

获取文件属性,path文件属性,buf传出参数存放文件属性,成功返回0,失败返回-1。

使用ln -s 创建软连接,然后查看对应的连接文件时,stat函数会”穿透“符号连接,使用stat判断文件类型时会显示连接的原文件属性,而使用lstat函数则不会出现此情况。

使用lstat函数查看文件类型:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>

int main(int argc, char *argv[]){
	struct stat sb; 
	int ret = lstat(argv[1], &sb); 
	if(ret == -1){
		perror("stat error");
		exit(1);
	}
	
	if(S_ISREG(sb.st_mode)) {
		printf("It's a regular\n");
	} else if (S_ISDIR(sb.st_mode)) {
		printf("It's a dir\n");
	} else if (S_ISFIFO(sb.st_mode)) {
		printf("It's a pipe\n");
	} else if (S_ISLNK(sb.st_mode)) {
		printf("It's a sym link\n");
	}

	return 0;
}

获取文件大小:buf.st_size

获取文件类型:buf.st_mode

获取文件权限:buf.st_mode

link&unlink函数

#include <unistd.h>

原型:int link(const char *oldpath, const char *newpath);

           int unlink(const char*pathname);

返回值:成功0,失败-1 并设置errno

为已存在的文件创建目录项以及删除一个文件的目录项

使用link和unlink实现文件改名操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>

int main(int argc, char *argv[]){
	link(argv[1], argv[2]);
	unlink(argv[1]);
	return 0;
}

Linux下删除文件的机制是不断将st_nlink减一直到0,无目录项对应的文件将会被操作系统择机释放。删除文件的操作只是让文件具备了被释放的条件。

unlink函数的特征:清除文件时,如果文件的硬链接数到0,没有dentry对应,但该文件不会被马上释放,要等到所有打开该文件的进程关闭该文件,系统才会挑时间释放该文件。

隐式回收

当进程结束运行时,所有该进程打开的文件会被关闭,申请的内存空间会被释放。系统的这一特性称之为隐式回收系统资源。(不可依赖该特性)

文件、目录权限

注:目录文件也是文件,其文件内容是该目录下所有子文件的目录项

目录操作

opendir函数

原型:DIR *opendir(const char *name);

根据传入的目录名打开一个目录(库函数),成功返回指向该目录的结构体指针,失败返回NULL

closedir函数

原型:int closedir(DIR *dirp);

关闭打开的目录,成功返回0,失败返回-1并设置errno为相应值

readdir函数

原型:struct dirent *readdir(DIR *dirp);

读取目录,成功返回目录项结构体指针,失败返回NULL并设置errno为相应值

struct dirent {
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* not an offset; see NOTES */
    unsigned short d_reclen;    /* length of this record */
    unsigned char  d_type;      /* type of file; not supported
                                   by all filesystem types */
    char           d_name[256]; /* filename */
};

见文件名大小,可知文件名长度最长为256-1=255个字节(不包括'\0')

getcwd函数

原型:char *getcwd(char *buf, size_t size);

获取进程当前工作目录,成功:buf保存当前进程工作目录位置;失败:返回NULL

chdir函数(系统调用)

原型:int chdir(const char *path);

改变当前进程工作目录,成功返回0,失败返回-1并设置errno为相应值

使用opendir和readdir实现命令ls的功能:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>

int main(int argc, char *argv[]){
	DIR *dp; 
	struct dirent *sdp;
	dp = opendir(argv[1]);
	if(dp == NULL){
		perror("opendir error");
		exit(1);
	}

	while((sdp = readdir(dp)) != NULL){
		if(strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0)
			continue; //去除对于隐藏文件的显示
		printf("%s\t", sdp->d_name);
	}
	printf("\n");	
	closedir(dp);
	
	return 0;
}

实现递归遍历ls -R的效果且打印文件大小:

step1. 判断命令行参数,获取用户要查询的目录名 argv[1]  argc == 1 ——> ./

step2. 判断用户指定的是否是目录 stat S_ISDIR() 封装一个函数 isFile

step3. 读目录 opendir() readdir() closedir()

递归的方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/stat.h>
#define PATH_LENGTH 256
void isFile(char *name);

// 打开目录读取,处理目录
void read_dir(char *dir){
	char path[256];
	DIR *dp; 
	struct dirent *sdp;
	dp = opendir(dir);
	if(dp == NULL){
		perror("opendir error");
		return; 
	}
	// 读取目录项
	while((sdp = readdir(dp)) != NULL){
		if(strcmp(sdp->d_name, ".") ==0 || strcmp(sdp->d_name, "..") == 0){
		    continue;
	    }
        // 目录项本身不可访问,拼接目录/目录项
		sprintf(path, "%s/%s", dir, sdp->d_name); 
        // 判断文件类型,目录则递归进入,文件显示名字和大小
		isFile(path);
	}
	closedir(dp);
	return;
}

 
void isFile(char *name){
	int ret = 0;
	struct stat sb;
    // 获取文件属性,判断类型
	ret = stat(name, &sb);
	if(ret == -1){
		perror("stat error");
		return;
	}
	if(S_ISDIR(sb.st_mode)){
		read_dir(name);
	}
	printf("%10s\t%ld\n", name, sb.st_size);
	return;
}

int main(int argc, char *argv[]){
    // 判断命令行参数
	if(argc == 1){
		isFile(".");	
	} else {
		isFile(argv[1]);
	}
	return 0;
}

回调的方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/stat.h>
#define PATH_LENGTH 256
void isFile(char *name);

void read_dir(char *dir, void(*func)(char*)){
	char path[256];
	DIR *dp; 
	struct dirent *sdp;
	dp = opendir(dir);
	if(dp == NULL){
		perror("opendir error");
		return; 
	}
	
	while((sdp = readdir(dp)) != NULL){
		if(strcmp(sdp->d_name, ".") ==0 || strcmp(sdp->d_name, "..") == 0){
		continue;
	}
		sprintf(path, "%s/%s", dir, sdp->d_name);
		//isFile(path);
		(*func)(path);
	}
	closedir(dp);
	return;
}

void isFile(char *name){
	int ret = 0;
	struct stat sb;
	ret = stat(name, &sb);
	if(ret == -1){
		perror("stat error");
		return;
	}
	if(S_ISDIR(sb.st_mode)){
		read_dir(name, isFile);
	}
	printf("%10s\t%ld\n", name, sb.st_size);
	return;
}

int main(int argc, char *argv[]){
	if(argc == 1){
		isFile(".");	
	} else {
		isFile(argv[1]);
	}
	return 0;
}

重定向

dup函数

原型:int dup(int oldfd);

使用现有的文件描述符拷贝一个新的文件描述符,函数调用前后两个文件描述符指向同一文件

成功返回一个新的文件描述符,失败返回-1并设置errno为相应值

dup2函数

原型:int dup2(int oldfd, int newfd);

实现命令行“重定向”功能。使得原来指向某文件的文件描述符,指向其他指定文件

成功:返回新的文件描述符newfd,若oldfd有效,则返回的文件描述符和oldfd指向同一文件

失败:若oldfd无效,关闭newfd,返回-1并设置errno为相应值

dup2之后执行write newfd将对oldfd文件进行操作。

fcntl实现dup描述符:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>

int main(int argc, char *argv[]){
	int fd1 = open(argv[1], O_RDWR);
	printf("fd1 = %d\n",fd1);
	int newfd = fcntl(fd1, F_DUPFD, 0); // 0被占用,fcntl使用文件描述符表中可用的最小文件描述符返回
	printf("newfd = %d\n", newfd);
	int newfd2 = fcntl(fd1, F_DUPFD, 7); // 7未被占用,返回=7的文件描述符
	printf("newfd2 = %d\n", newfd2);
	
	int ret = write(newfd2, "YYYY", 7);
	printf("ret=%d\n", ret);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值