文件信息显示

文件信息显示

1. 实现方法简介

首先,分析题干给出的要求:通过命令行程序,显示一个文件夹中所有的子文件夹文件信息。因此,实现该程序的时候不仅要通过递归的方式寻找出所有的文件夹,还要能够通过命令行参数来设置根文件夹的路径。

在实现算法之前,首先确定语言,根据我的熟悉程度,我首先用Python试水,然后使用C++实现递归显示。

根据核心代码展示顺序,我先对C++实现算法进行简介。

通过搜集资料,首先我认识到,命令行参数的设置和int main(int argc, char* argv[])中的参数密切相关,argc 代表命令行中参数的个数(包含可执行程序!!!),而argv则是存储各个命令行参数的列表。所以相对于python而言,C++调用命令行参数要方便得多。在我的命令行设计中,格式为:XXX.exe ROOT_PATH,共计两个参数,所以argc=2,而实现显示文件信息所必要的参数root_path,则通过argv[1]即可传递。

设计函数为两个,一是寻找根目录下所有文件,并将绝对路径保存到列表files中的函数:

void Find_AllFiles(std::string  root_path, std::vector<std::string>& files)

第二是接受命令行参数,并显示子文件夹及文件信息的函数:

void Reveal_File_Info(int argc, char* argv[])

函数Find_AllFiles通过vector容器实现对文件列表的信息扩展及添加。

对于文件的查找,可以通过io.h中的 _findfirst、 _findnext、 _findclose三个函数配合查找,找出文件的句柄(是一个顺序号,是识别打开文件的唯一识别证据)并且把文件信息保存到 _finddata_t型的结构体fileinfo中

_finddata_t型的结构体在宏定义中被定义为 _finddata64i32_t

struct _finddata64i32_t
{
    unsigned    attrib;
    __time64_t  time_create;    // -1 for FAT file systems
    __time64_t  time_access;    // -1 for FAT file systems
    __time64_t  time_write;
    _fsize_t    size;
    char        name[260];
};

因此可以通过该结构体中的元素得到该文件的各个属性值。而attrib尤其方便,它通过数值能表示:

#define _A_NORMAL 0x00 // Normal file - No read/write restrictions
#define _A_RDONLY 0x01 // Read only file
#define _A_HIDDEN 0x02 // Hidden file
#define _A_SYSTEM 0x04 // System file
#define _A_SUBDIR 0x10 // Subdirectory
#define _A_ARCH   0x20 // Archive file

所以可以通过attrib来判断是否是子文件,从而实现递归起始条件的判断。

而第二个函数Reveal_File_Info则是主要通过对结构体fileinfo的操作,显示文件的属性。

在Python实现中,由于有两个好用的包,实现简单了很多。在对于文件的查找中,可以通过os.walk方法,但是os.path.walk被pathlib中的Path替代(因为pathlib中的路径和文件通过面向对象的方法实现,封装更好)通过pathlib.Path方法可以直接通过root_path直接得到,并且通过stat()方法得到属性。

但是对于python,命令行不是很方便实现,通过click包,可以将命令行参数绑定到某些函数中,如command()函数,借用别的函数的接口来是按对于命令行参数的获取。

2. 核心代码
C++实现
void Find_AllFiles(std::string  root_path, std::vector<std::string>& files) {
	intptr_t hFile = 0;//文件句柄
	struct _finddata_t fileinfo;//文件信息
	std::string p;
	if ((hFile = _findfirst(p.assign(root_path).append("\\*").c_str(), &fileinfo)) != -1)
    {
		do {
			if ((fileinfo.attrib & _A_SUBDIR)) {  //比较文件类型是否是文件夹
				if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) 
                {
                 files.push_back(p.assign(root_path).append("\\").append(fileinfo.name));
                    std::cout << "子文件夹:" << p << std::endl;
					//递归搜索
			Find_AllFiles(p.assign(root_path).append("\\").append(fileinfo.name), files);
				}
			}
			else {
				files.push_back(p.assign(root_path).append("\\").append(fileinfo.name));
			}
		} while (_findnext(hFile, &fileinfo) == 0);  //寻找下一个,成功返回0,否则-1
		_findclose(hFile);
	}
}

void Reveal_File_Info(int argc, char* argv[]) {
	// argc == 2
	// argv[1] == root_path
	intptr_t   hFile = 0;//文件句柄
	std::vector<std::string> files_list;
	if (argc != 2) {
		std::cout << "please type the root path" << std::endl;
	}
	else {
		Find_AllFiles(argv[1], files_list);
		std::string p;
		struct _finddata_t fileinfo;//文件信息
		for (unsigned int i = 0; i < files_list.size(); ++i) {
			hFile = _findfirst(p.assign(files_list[i]).c_str(), &fileinfo);
			std::cout << std::endl;
			std::cout << "绝对路径:" << files_list[i] << std::endl;
			std::cout << "文件属性:" << fileinfo.attrib << std::endl;
			std::cout << "文件名称:" << fileinfo.name << std::endl;
			std::cout << "文件大小:" << fileinfo.size << std::endl;
			std::cout << "文件最后一次被访问的时间:" << fileinfo.time_access << std::endl;
			std::cout << "创建时间:" << fileinfo.time_create << std::endl;
			std::cout << "文件最后一次被修改的时间:" << fileinfo.time_write << std::endl;
			std::cout << std::endl;
		}
	}
}
Python实现
import pathlib
import click


@click.command()
@click.option('--path', 'root_path', prompt='Directory Path', default=1, help='The Path of Directory you wanna reveal.', type=str)
def Reveal_File_Info(root_path):
    root_dir = pathlib.Path(root_path)
    for file_path in root_dir.rglob('*'):
        click.echo()
        click.echo("绝对路径: " + str(file_path))
        click.echo("文件名: " + file_path.name)
        click.echo("扩展名: " + file_path.suffix)
        click.echo("inode保护模式: " + str(file_path.stat().st_mode))
        click.echo("inode节点号: " + str(file_path.stat().st_ino))
        click.echo("inode驻留的设备: " + str(file_path.stat().st_dev))
        click.echo("inode的链接数: " + str(file_path.stat().st_nlink))
        click.echo("所有者的用户ID: " + str(file_path.stat().st_uid))
        click.echo("所有者的组ID: " + str(file_path.stat().st_gid))
        click.echo("普通文件的大小: " + str(file_path.stat().st_size) + " 字节")
        click.echo("上次访问的时间: " + str(file_path.stat().st_atime))
        click.echo("最后一次修改的时间: " + str(file_path.stat().st_mtime))
        click.echo("最新的元数据更改的时间(如Unix)/创建时间(如Windows): " + str(file_path.stat().st_ctime))
        click.echo()

结果

3. PSP表格
PSP各阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
· Estimate · 明确需求和其他因素,估计以下各个任务需要多少时间 5 5
Development 开发
· Analysis · 需求分析 (包括学习新技术、新工具的时间) 20 60
· Design Spec · 生成设计文档(整体框架的设计,各模块的接口) 5 2
· Design Review · 设计复审 (和同事审核设计文档) 5 0
· Coding Standard · 代码规范 (为目前的开发制定或选择合适的规范) 5 1
· Design · 具体设计(用流程图、伪代码等方法来设计具体模块) 5 1
· Coding · 具体编码 30 60
· Code Review · 代码复审 10 10
· Test · 测试(自我测试,修改代码,提交修改) 40 85
Reporting 报告
· Test Report · 测试报告(发现了多少bug,修复了多少) 10 8
· Size Measurement · 计算工作量(多少行代码,多少次签入,多少测试用例,其他工作量) 5 2
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划(包括写文档、博客的时间) 30 40
合计 170 274
posted @ 2020-10-19 08:58  该用户已住校  阅读(60)  评论(0)    收藏  举报