File System
- 1. Getting Files and Folders
- 1.1. Getting Files and Folders using Paths
- 1.2. Getting Files and Folders using Parent Folders
- 1.3. Getting Special Folders
- 2. Creating Files and Folders
- 3. Deleting Files and Folders
- 4. Traversing Folders
- 5. Getting the Contents of Folders
- 6. Reading and Writing Files
- 7. Troubleshooting
1. Getting Files and Folders
1.1. Getting Files and Folders using Paths
To get a file or folder from an absolute path:
File path: '/usr/lib/libiodbc.dylib'. => MacFile path: '/usr/lib/libiodbc.2.dylib' Directory path: '/usr/lib' => MacDirectory path: '/usr/lib'
To get a file from a path relative to another folder:
File path: 'lib/libiodbc.dylib' relativeTo: (Directory path: '/usr') => MacFile path: '/usr/lib/libiodbc.2.dylib' or (Directory path: '/usr') relativePath: 'lib/libiodbc.dylib' => MacFile path: '/usr/lib/libiodbc.2.dylib'
To get a folder from a path relative to another folder:
Directory path: 'lib' relativeTo: (Directory path: '/usr') => MacDirectory path: '/usr/lib' or (Directory path: '/usr') relativePath: 'lib' => MacDirectory path: '/usr/lib'
1.2. Getting Files and Folders using Parent Folders
To get a file or folder from the given parent folder:
(Directory path: '/usr/lib') fileNamed: 'libiodbc.dylib' => MacFile path: '/usr/lib/libiodbc.dylib' (Directory path: '/usr') directoryNamed: 'lib' => MacDirectory path: '/usr/lib'
1.3. Getting Special Folders
The current directory can be obtained by the following expression. Note that this is really only useful if Smalltalk is run from the command line.
Directory current => MacDirectory path: '/Users/Mark'
If Smalltalk is run from the Finder (i.e. by double clicking the application icon), the current folder is the root directory.
Directory current => MacDirectory path: '/'
To get the application folder:
Directory application => MacDirectory path: '/Applications'
To get the application package folder:
MacDirectory applicationPackage => MacDirectory path: '/Applications/Smalltalk.app'
To get the application resource folder:
MacDirectory applicationResources => MacDirectory path: '/Applications/Smalltalk.app/Contents/Resources'
To get the current user and system application support directory where plugins can be stored:
MacDirectory userApplicationSupport => MacDirectory path: '/Users/Mark/Library/Application Support' MacDirectory systemApplicationSupport => MacDirectory path: '/Library/Application Support'
To get the user specific preferences folder:
MacDirectory userPreferences => MacDirectory path: '/Users/Mark/Library/Preferences'
To get the desktop directory for the current user:
Directory desktop => MacDirectory path: '/Users/Mark/Desktop'
To get the MacOS X system folder:
Directory system => MacDirectory path: '/System'
To get the current user trash folder:
MacDirectory trash => MacDirectory path: '/Users/mark/.Trash'
To get the current user and system temporary folders:
MacDirectory userTemporary => MacDirectory path: '/Users/Mark/Library/Caches/TemporaryItems' MacDirectory systemTemporary => MacDirectory path: '/private/var/tmp/folders.501/TemporaryItems'
2. Creating Files and Folders
2.1. Creating new Files and Folders
You must first get the directory in which you want to create a new file or directory, then create it by name.
Directory desktop createFileNamed: 'untitled.txt'. Directory desktop createDirectoryNamed: 'Untitled Folder'.
2.2. Creating Files and Folders that may Already Exist
If there is a file or directory that you want to create but you expect that it may already exist, then you can create or return the existing item.
Directory desktop createFileIfDoesNotExist: 'untitled.txt'. Directory desktop createDirectoryIfDoesNotExist: 'Untitled Folder'.
3. Deleting Files and Folders
You can delete files and folders via the #delete method:
(Directory desktop fileNamed: 'untitled.txt') delete. (Directory desktop directoryNamed: 'Untitled Folder') delete
4. Traversing Folders
You can enumerate the files, folders, or files and folders together for a given folder:
Directory desktop filesDo: [:each | Transcript print: each; cr]. Directory desktop directoriesDo: [:each | Transcript print: each; cr]. Directory desktop filesAndDirectoriesDo: [:each | Transcript print: each; cr].
5. Getting the Contents of Folders
You can get a collection of files, folders, or files and folders together for a given folder:
Directory desktop files. Directory desktop directories. Directory desktop filesAndDirectories.
6. Reading and Writing Files
6.1. Reading and Writing Entire Files
You can read or write the entire contents of a file at once using these accessor methods: #asciiContents, #asciiContents:, #utf8Contents, #utf8Contents:, #utf16Contents, #utf16Contents, #binaryContents, #binaryContents:. You should do this only if the file is small, otherwise you should use a file stream to read or write the file in pieces.
Here is an example of writing and reading a file all at once:
(Directory desktop createFileIfDoesNotExist: 'untitled.txt') utf8Contents: 'cześć'. Transcript nextPutAll: (Directory desktop fileNamed: 'untitled.txt') utf8Contents.
6.2. Reading and Writing Files using Streams
For larger files you will want to open a stream and read or write in pieces. Once you are finished you should close the stream. If you do not close an open file stream, then the finalization mechanism of the garbage collector will do this for you automatically, however, there is no guarantee as to how soon this will happen.
To read from an existing file:
| file stream | file := Directory desktop fileNamed: 'untitled.txt'. stream := file openForReading. [ "read from the file stream here" ] ensure: [stream close].
To append to an existing file:
| file stream | file := Directory desktop fileNamed: 'untitled.txt'. stream := file openForWriting. [ stream setToEnd. "write to the file stream here" ] ensure: [stream close].
To create a new file or to overwrite an existing file:
| file stream | file := Directory desktop createFileIfDoesNotExist: 'untitled.txt'. stream := file openForWriting. [ stream truncate. "write to the file stream here" ] ensure: [stream close].
To write to a text file using a stream:
| file stream | file := Directory desktop createFileIfDoesNotExist: 'untitled.txt'. stream := file openForWriting. [ stream beAscii; truncate; nextPutAll: 'Hello World!'; cr ] ensure: [stream close].
To write to a text file using an encoded stream:
| file stream | file := Directory desktop createFileIfDoesNotExist: 'untitled.txt'. stream := file openForWriting. [ stream beBinary; truncate. stream := stream asEncodingStream: 'UTF-8'. stream nextPutAll: 'Cześć świat!'; cr ] ensure: [stream close].
To print an UTF-8 encoded text file to the Transcript line by line:
| file stream | file := Directory desktop fileNamed: 'untitled.txt'. stream := file openForReading. [ stream beBinary. stream := stream asDecodingStream: 'UTF-8'. [stream atEnd] whileFalse: [ Transcript nextLinePut: stream nextLine] ] ensure: [stream close].
7. Troubleshooting
7.1. Modifying a folder while traversing it
It is not a good idea to modify a folder while directly enumerating over its contents. This is because #filesDo:, #directoriesDo:, and #filesAndDirectoriesDo: methods use the native file system iterators which are sensitive to file creation and deletion.
For example, do not delete files from a folder as you traverse it:
Directory desktop filesDo: [:eachFile | eachFile extension = 'tmp' ifTrue: [eachFile delete]].
Instead, delete them as you enumerate over a cached version of the folder contents:
| files | files := OrderedCollection new. Directory desktop filesDo: [:eachFile | files add: eachFile]. files do: [:eachFile | eachFile extension = 'tmp' ifTrue: [eachFile delete]].
Alternatively, use the #files method which returns a collection of the folder contents:
Directory desktop files do: [:eachFile | eachFile extension = 'tmp' ifTrue: [eachFile delete]].
All #files, #directories, and #filesAndDirectories methods build and return a collection containing the folder contents and it is safe to modify the folder while traversing this collection.
Last modified May 18, 2006.