AnyMath 文档
Notebook

高级文件管理

让我们想象一个情况,我们有几个数据集分布在文件夹中,文件夹中也可能有垃圾(带有有趣浣熊的图片,文本文档)。 我希望能够找到必要的文件,以便以后与他们一起工作。 Julia只实现文件的基本工作-<https://engee.com/helpcenter/stable/ru-en/julia/base/file.html >。

在这篇文章中,我将制作一个更聪明的工具来处理文件。

我们将如何工作?

我们不会进入文件系统如何工作的细节-我们不需要它。 只要观察到目录和文件的结构惊人地类似于一棵树就足够了。 树是一种特殊的图形。 在这样的图中,除了"根"之外的所有节点都有一个父节点。:

image.png

用于图遍历和图修改的最优算法对于这样的图是已知的,并且它们通常已经实现。 我的想法如下:我将文件夹的内容表示为一棵树,树的每个节点都是一个文件或文件夹。 我将分别保留路径,名称,扩展名,创建和修改的日期和时间,以及文件夹属性。 并且为了组织一个树结构,我将存储这个节点的"后代"。:

In [ ]:
using Dates

struct FileTreeNode
    path::String
    name::String
    ext::String
    isdir::Bool
    created::DateTime
    modified::DateTime
    children::Vector{FileTreeNode}
end

此外,我们还将创建辅助函数来获取文件创建和修改的日期和时间,以及获取文件名、路径和扩展名。:

In [ ]:
function get_metadata(path::String)
    st = stat(path)

    created = unix2datetime(st.ctime)
    modified = unix2datetime(st.mtime)

    return created, modified
end

function split_name_ext(path::String)
    name = basename(path)
    base, ext = splitext(name)
    return base, ext
end
Out[0]:
split_name_ext (generic function with 1 method)

种植一棵树

我们有一切需要实现,我们可以创建一个基于目录结构的树。

使用 readdir 我们将获取当前文件夹内的文件和文件夹列表,然后对检测到的文件夹重复此操作。 这称为递归。

以编程方式,我们执行文件和文件夹树的递归遍历。**

让我们为我们的功能添加一个限制:搜索深度。

In [ ]:
function build_tree(path::String; maxdepth=typemax(Int), depth=0)
    is_dir = isdir(path)

    name, ext = split_name_ext(path)
    created, modified = get_metadata(path)
    if is_dir && depth < maxdepth
        entries = readdir(path; join=true)
        children = [
            build_tree(e; maxdepth, depth=depth+1)
            for e in sort(entries)
        ]
    else
        children = FileTreeNode[]
    end

    return FileTreeNode(path, name, ext, is_dir, created, modified, children)
end
Out[0]:
build_tree (generic function with 1 method)
In [ ]:
import AbstractTrees: children, printnode

children(node::FileTreeNode) = node.children

function printnode(io::IO, node::FileTreeNode)
    if node.isdir
        print(io, "📁 ", node.name)
    else
        print(io, "📄 ", node.name, node.ext)
    end
end
Out[0]:
printnode (generic function with 5 methods)
In [ ]:
tree = build_tree(".",maxdepth=2)
using AbstractTrees: print_tree
print_tree(tree)
nothing