How to work with the file system

Glamorous Toolkit, like any Smalltalk system, is built around an image. That does not mean it can't communicate with the outside world, like the file system. On the contrary. The file system is nicely modelled inside the image. For example, inspect this:

'.' asFileReference
  

This page described basic operations for working with files and directories.

The class FileReference AbstractFileReference << #FileReference slots: { #filesystem }; tag: 'Public'; package: 'FileSystem-Core' provides the main high-level API for working with files and folders. It holds a Path Object << #Path layout: VariableLayout; slots: {}; tag: 'Base'; package: 'FileSystem-Path' and a FileSystem Object << #FileSystem slots: { #store }; tag: 'Public'; package: 'FileSystem-Core' and can manipulate File Object << #File slots: { #name }; sharedVariables: { #S_IFIFO . #Registry . #S_IFCHR . #S_IFREG . #S_IFMT . #S_IFLNK . #S_IFBLK . #S_IFDIR . #S_IFSOCK }; tag: 'Core'; package: 'Files' objects, which provide the basic set of operations for working files on disk.

A Path Object << #Path layout: VariableLayout; slots: {}; tag: 'Base'; package: 'FileSystem-Path' abstracts locations on the file system, and can be relative or absolute. FileSystem Object << #FileSystem slots: { #store }; tag: 'Public'; package: 'FileSystem-Core' defind protocol for interacting with filesystems. It hold a reference to a concrete store (a subinstance of FileSystemStore Object << #FileSystemStore slots: {}; tag: 'Kernel'; package: 'FileSystem-Core' ) where files are saved; this can be on disk (DiskStore FileSystemStore << #DiskStore slots: { #maxFileNameLength }; sharedVariables: { #CurrentFS . #DefaultWorkingDirectory }; tag: 'Store'; package: 'FileSystem-Disk' ) or in memory (MemoryStore FileSystemStore << #MemoryStore slots: { #root }; sharedVariables: { #CurrentFS }; tag: 'Store'; package: 'FileSystem-Memory' ).

The method AbstractFileReference>>#writeStreamDo: writeStreamDo: aBlock | stream | stream := self writeStream. ^ [ aBlock value: stream ] ensure: [ stream close ] writes to a file using a utf8-encoded buffered character stream. It gets the stream as a parameter, and makes sure the stream gets closed after writting is done.

textFile := './example.txt' asFileReference.
textFile writeStreamDo: [ :aStream | 
	aStream nextPutAll: 'Content in a text file' ].
textFile
  

The method AbstractFileReference>>#readStreamDo: readStreamDo: aBlock | stream | stream := self readStream. ^ [ aBlock value: stream ] ensure: [ stream close ] reads the content of a text file using a utf8-encoded buffered character stream.

textFile := './example.txt' asFileReference.
contents := nil.
textFile readStreamDo: [ :aStream | 
	contents := aStream contents ].
contents
  

A stream allows us to read the content in chunks. In case we are simply interested in the entire content we can use AbstractFileReference>>#contents contents self readStreamDo: [ :stream | ^ stream contents ] .

textFile := './example.txt' asFileReference.
contents := textFile contents