Skip to main content
Engineering LibreTexts

2.6: Looking at FileSystem Internals

  • Page ID
    43797
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    At that stage, you should be able to comfortably use FileSystem to cover your need file handing. This section is about the internal components of FileSystem. It goes over important implementation details, which will surely interest readers willing to have a new kind of file system, for example on a data base or a remote file system.

    FileReference = FileSystem + Path

    Paths and filesystems are the lowest level of the FileSystem API. A FileReference combines a path and a filesystem into a single object which provides a simpler protocol for working with files as we show in the previous section. References implement the path protocol with methods like /, parent and resolve:.

    FileSystem

    A filesystem is an interface to access hierarchies of directories and files. "The filesystem," provided by the host operating system, is represented by DiskStore and its platform-specific subclasses. However, the user should not access them directly but instead use FileSystem as we showed previously. Other kinds of filesystems are also possible. The memory filesystem provides a RAM disk filesystem where all files are stored as ByteArrays in the image. The zip filesystem represents the contents of a zip file.

    Each filesystem has its own working directory, which is used to resolve any relative paths that are passed to it. Some examples:

    fs := FileSystem memory.
    fs workingDirectoryPath: (Path / 'plonk').
    griffle := Path / 'plonk' / 'griffle'.
    nurp := Path * 'nurp'.
    fs resolve: nurp.
        →    Path/plonk/nurp
    
    fs createDirectory: (Path / 'plonk').    → "/plonk created"
    (fs writeStreamOn: griffle) close.       → "/plonk/griffle created"
    fs isFile: griffle.                      → true
    fs isDirectory: griffle.                 → false
    fs copy: griffle to: nurp.               → "/plonk/griffle copied to /plonk/nurp"
    fs exists: nurp.                         → true
    fs delete: griffle.                      → "/plonk/griffle" deleted
    fs isFile: griffle.                      → false
    fs isDirectory: griffle.                 → false
    

    Path

    Paths are the most fundamental element of the FileSystem API. They represent filesystem paths in a very abstract sense, and provide a high-level protocol for working with paths without having to manipulate strings. Here are some examples showing how to define absolute paths (/), relative paths (*), file extension (,), parent navigation (parent). Normally you do not need to use Path but here are some examples.

    | fs griffle nurp |
    fs := FileSystem memory.
    griffle := fs referenceTo: (Path / 'plonk' / 'griffle').
    nurp := fs referenceTo: (Path * 'nurp').
    griffle isFile.
        → false
    griffle isDirectory.
        → false
    griffle parent ensureCreateDirectory.
    griffle ensureCreateFile.
    griffle exists & griffle isFile.
        → true
    griffle copyTo: nurp.
    nurp exists.
        → true
    griffle delete 
    
    "absolute path"
    Path / 'plonk' / 'feep'                → /plonk/feep
    
    "relative path"
    Path * 'plonk' / 'feep'                → plonk/feep
    
    "relative path with extension"
    Path * 'griffle' , 'txt'               → griffle.txt
    
    "changing the extension"
    Path * 'griffle.txt' , 'jpeg'          → griffle.jpeg
    
    "parent directory"
    (Path / 'plonk' / 'griffle') parent    → /plonk
    
    "resolving a relative path"
    (Path / 'plonk' / 'griffle') resolve: (Path * '..' / 'feep')
        → /plonk/feep
    
    "resolving an absolute path"
    (Path / 'plonk' / 'griffle') resolve: (Path / 'feep')
        → /feep
    
    "resolving a string"
    (Path * 'griffle') resolve: 'plonk'    → griffle/plonk
    
    "comparing"
    (Path / 'plonk') contains: (Path / 'griffle' / 'nurp')
        → false
    

    Note that some of the path protocol (messages like /, parent and resolve:) are also available on references.

    Visitors

    The above methods are sufficient for many common tasks, but application developers may find that they need to perform more sophisticated operations on directory trees.

    The visitor protocol is very simple. A visitor needs to implement visitFile: and visitDirectory:. The actual traversal of the filesystem is handled by a guide. A guide works with a visitor, crawling the filesystem and notifying the visitor of the files and directories it discovers. There are three Guide classes, PreorderGuide, PostorderGuide and BreadthFirstGuide, which traverse the filesystem in different orders. To arrange for a guide to traverse the filesystem with a particular visitor is simple. Here’s an example:

    BreadthFirstGuide show: aReference to: aVisitor
    

    The enumeration methods described above are implemented with visitors; see CopyVisitor, DeleteVisitor, and CollectVisitor for examples.


    This page titled 2.6: Looking at FileSystem Internals is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.