Pharo 或 Squeak:如何以递归方式获取目录和文件列表

问题描述 投票:0回答:3

首先:我不是程序员,只是一个对 Squeak/Pharo 有一些了解的业余爱好者。所以请对技术解释保持温和......

我有一个个人图书馆,里面有数千本书、文章等,有些是纸质的,有些是数字支持的。除非我能够对所有内容进行组织和分类,否则所有这些都是垃圾。

我认为使用 Smalltalk 这将是一项简单的任务。

我创建了 3 个主要类:

Object>>Cards 
    inst. var: name, localAdress, notes, tags, ...
Cards>>Work 
    inst. var: authors "aSet of Cards"
Cards>>Author
Object>>MyLibrary
    inst var: works "aSet of Cards" authors "aSet of Cards" myLibraryBase "aString? aPath?"

简单明了。 MyLibrary 的实例 #initialize 使用 UIManager 选择目录,以明确必须找到文件的位置。

现在我的问题是:我应该为 MyLibrary 创建一个方法来“扫描”myLibraryBase 下所有文件夹和子文件夹中的所有相关文件(后缀)。意思是,该方法应该回答文件集合。此方法或其他方法应进一步为集合中找到的每个文档创建一个新卡,注册其本地地址。

我根本不知道该怎么做。我在文件系统下尝试了#allDirectories,但它不起作用。另外,我不知道如何强制文件系统从 myLibraryBase 启动,而不是 root、workingDirectory 等。

有人能指出我正确的方向吗? 谢谢

filesystems pharo squeak
3个回答
1
投票

用 Squeak 来补充 @MartinW 的答案:

@MartinW 的答案使用了 FileSystem 编程接口,该接口在 Squeak 中不可用,但可以作为扩展安装:https://github.com/squeak-smalltalk/squeak-filesystem

对于普通的 Squeak,人们必须使用 FileDirectory 编程接口。它具有类似的消息,但它们的处理方式与其他答案中提到的

allChildren
不同。

比如有一条消息叫

withAllSubdirectoriesCollect:
, 它评估树中每个目录的代码块,并从 您可以获取所有包含的文件的目录。

(UIManager default
    chooseDirectory: 'Select directory of the collection'
    from: FileDirectory default) "This will result in a FileDirectory object unless you cancel the dialog."
    withAllSubdirectoriesCollect:
         [:eachDirectory | "eachDirectory is a FileDirectory object."
         eachDirectory fileEntries do: "This loops through all the files (not subdirectories) in eachDirectory."
              [:eachFileEntry | "eachFileEntry is a DirectoryEntry object."
              Transcript show: eachFileEntry fullName; cr]]

请在 Squeak 中查找 FileDirectory 和 DirectoryEntry 类 了解您可以用它们做什么,并提出任何进一步的问题 你可能有。

除了将文件名写入转录本之外,您还可以 将目录条目放入您的收藏中以便以后处理,或者先将它们转换为卡片并直接添加到您的图书馆中。


还有另一条消息,其中还包括 直接遍历,不仅仅是目录(所以不需要两个 嵌套的代码块),但它的接口可能看起来有点令人惊讶:它被称为

directoryTreeDo:
,它评估每个文件的代码块,并且 目录。作为此代码块的参数,它提供了一个列表 指向此文件或目录的 DirectoryEntries...但是如果您只查看最后一个 输入提供的列表,您应该能够获得您想要的所有内容 每个文件都需要。

这是一个例子:

(UIManager default
    chooseDirectory: 'Select directory of the collection'
    from: FileDirectory default)
    directoryTreeDo: [:each | Transcript show: each last fullName; cr]
块中的

each last
是当前文件的DirectoryEntry或 目录。例如,您可以通过测试仅查找文件 与
each last isFile

...
directoryTreeDo:
    [:each |
    each last isFile ifTrue:
         [Transcript show: each last fullName; cr]]

0
投票

在 Pharo 中,您可以尝试这个作为开始。我在示例中使用了

jpg
扩展。如果您使用
children
您将获得当前文件夹。如果您使用
allChildren
,则包含子文件夹:

| folder imageFiles |
folder := '/path/to/your/folder' asFileReference.
imageFiles := folder allChildren select: [ :each | each basename endsWith: 'jpg' ].

这个文档有点过时,但我认为它仍然适用:https://eng.libretexts.org/Bookshelves/Computer_Science/Programming_Languages/Book%3A_Deep_into_Pharo_(Bergel_Cassou_Ducasse_and_Laval)/02%3A_Files_with_FileSystem


0
投票

假设您有根目录(我认为您将其保留为 myLibraryBase?),那么您可以使用 FileDirectory>>#withAllFilesDo:andDirectoriesDo: 方法。

从一个目录开始,沿着树向下递归,并运行一个包含找到的每个文件的块和一个包含每个目录的单独块。从某些方面来说,它就像一把锤子来压碎蜗牛,但它的效果很好,所以为什么要重新发明螺丝刀呢?

举个例子 -

| list |
list := OrderedCollection new: 100.
FileDirectory default
    withAllFilesDo:[:fs| list  add: fs name]
    andDirectoriesDo:[:d| list add: d pathName].
list

检查它,您应该看到从默认目录开始的目录路径名列表,与该树中每个目录中找到的文件的全名混合在一起。它的速度也相当快;在我的 Pi 5 上,所有文件都位于非常普通的 microSD 卡上,需要 1.5 秒才能在我的 Squeak 主目录下的目录中构建包含 36,000 个文件的列表。

对于您的使用方式,值得记住的是,文件块获取找到的文件的文件流,因此读取它并一次性构建卡片比构建名称列表然后迭代到(重新构建)更有效)打开文件并处理它。

所以我猜是这样的

FileDirectory default
    withAllFilesDo:[:fs| Cards add: (Card readFrom: fs)]
    andDirectoriesDo:[:d|"do nothing with directory"]

可能是一个很好的举措。

© www.soinside.com 2019 - 2024. All rights reserved.