File
Standard library for filesystem operations.
Functions in this module let you read from and write to the filesystem. Many
functions accept a path, which can be relative to the current working
directory (see cwd()
) or absolute. The companion module
Path
can be used to operate on filesystem paths.
Filesystem operations have many error cases, so functions in this module can
raise a variety of exceptions, the most common ones being
Exists
, DoesntExist
,
EndOfFile
, PermissionDenied
, and
NotPermitted
.
To import all names from this module, use:
import File (*)
With no import, you can still access anything with the prefix File.
, like File.read_path
.
Index
Name | Type | Description |
---|---|---|
String -> String | Reads and returns the contents of the file at | |
(String, String) -> () | Writes | |
(String, String) -> Int | Copies the file at path | |
(String, String) -> () | Moves the file at path | |
String -> () | Removes the file at | |
String -> () | Removes the directory at | |
String -> [String] | Lists the files in the directory given by | |
String -> [String] | Returns a list of existing paths that match the glob pattern | |
String -> () | Makes a new directory at | |
String -> () | Makes a new directory at | |
String -> Bool | Returns true if | |
String -> Stat | Returns metadata about the file at | |
String -> Stat | Returns metadata about the file at | |
(String, OpenMode) -> Handle | Opens the file at | |
Handle -> () | Closes the file handle | |
(Handle, ReadAmount) -> String | Reads characters from the file given by | |
(Handle, String) -> () | Writes | |
(Handle, Int) -> () | Changes the file position of | |
Handle -> Int | Changes the file position of | |
Handle -> Int | Returns the file position of | |
Handle -> () | Truncates the file given by | |
() -> String | Returns the current working directory, which starts as the directory in which
| |
String -> () | Changes the current working directory to | |
String | The system's temporary directory. | |
() -> String | Makes a new temporary directory within | |
String -> String | Writes | |
(String, String) -> () | Creates a hard link at path | |
(String, String) -> () | Creates a symbolic link at path | |
String -> String | Resolves the symbolic link at | |
(String, Mode) -> () | Changes the access controls for the file at the given | |
(String, Int) -> () | Changes the owner of | |
(String, Int) -> () | Changes the group of | |
Stat | Contains metadata about a file. | |
FileType | Specifies the type of a file. | |
Mode | Contains access controls for a file. | |
Permissions | Specifies permissions when accessing a file. | |
OpenMode | Specifies what mode to open a file in. | |
Handle | Represents an open file handle returned by | |
ReadAmount | Specifies the amount to read from a file. |
Functions
read_path : String -> String read_path(path)
Reads and returns the contents of the file at path
.
assert read_path(write_temp("foo")) == "foo"
write_path : (String, String) -> () write_path(path, contents)
Writes contents
to the file at path path
.
let path = Path.join(make_temp_dir(), "new") write_path(path, "foo") assert read_path(path) == "foo"
cp : (String, String) -> Int cp(from, to)
Copies the file at path from
to path to
, overwriting to
if it exists.
Doesn't work with directories.
let path = write_temp("foo") let new_path = Path.join(make_temp_dir(), "new") cp(path, new_path) assert read_path(new_path) == "foo" assert read_path(path) == "foo"
mv : (String, String) -> () mv(from, to)
Moves the file at path from
to path to
, overwriting to
if it exists.
Doesn't work with directories.
let path = write_temp("foo") let new_path = Path.join(make_temp_dir(), "new") mv(path, new_path) assert read_path(new_path) == "foo" assert !exists?(path)
rm : String -> () rm(path)
Removes the file at path
. Doesn't work with directories; use
rmdir
.
let path = write_temp("") rm(path) assert !exists?(path)
rmdir : String -> () rmdir(path)
Removes the directory at path
. The directory must be empty to be removable.
let path = make_temp_dir() rmdir(path) assert !exists?(path)
ls : String -> [String] ls(path)
Lists the files in the directory given by path
. Returns a list of paths,
where each path starts with path
and is followed by a directory separator
and the filename.
let path = make_temp_dir() write_path(Path.join(path, "foo"), "") write_path(Path.join(path, "bar"), "") mkdir(Path.join(path, "baz")) assert to_set(ls(path)) == #["foo", "bar", "baz"]
glob : String -> [String] glob(pat)
Returns a list of existing paths that match the glob pattern pat
. pat
may
contain the following special sequences:
?
— Matches any one character.*
— Matches zero or more characters, excluding the directory separator.**
— Matches zero or more characters, including the directory separator.{foo,bar,...}
— Matches eitherfoo
orbar
or etc.[a,b,f-z,...]
— Matches either the single charactera
or the single characterb
or the range of charactersf
throughz
or etc.
All characters that aren't ?
, *
, {
, }
, [
, or ]
match themselves,
case-sensitive.
let path = make_temp_dir() let foo_path = Path.join(path, "foo") let bar_path = Path.join(path, "bar") let baz_path = Path.join(path, "baz-foo") write_path(foo_path, "") write_path(bar_path, "") mkdir(baz_path) assert to_set(glob(Path.join(path, "*"))) == #[foo_path, bar_path, baz_path] assert to_set(glob(Path.join(path, "*foo"))) == #[foo_path, baz_path] assert to_set(glob(Path.join(path, "{foo,bar}"))) == #[foo_path, bar_path]
mkdir : String -> () mkdir(path)
Makes a new directory at path
. All parent directories must exist; to create
parent directories as well, use mkdir_p()
.
let path = Path.join(make_temp_dir(), "new") mkdir(path) assert stat(path).type == Directory
mkdir_p : String -> () mkdir_p(path)
Makes a new directory at path
, creating parent directories if need be.
let path = Path.join_all([make_temp_dir(), "new", "sub"]) mkdir_p(path) assert stat(path).type == Directory
exists? : String -> Bool exists?(path)
Returns true if path
exists (regardless of whether it's a file, directory,
device, etc.). If path
is a symbolic link, returns true if the target path
it refers to exists.
assert exists?(write_temp("")) assert exists?(make_temp_dir()) assert !exists?(Path.join(make_temp_dir(), "new")) assert !exists?("asdf")
stat : String -> Stat stat(path)
Returns metadata about the file at path
. If path
is a symbolic link,
resolves it and returns info about the target path it refers to. See the
Stat
struct for details on the result.
let contents = "hello" let path = write_temp(contents) let mode = Mode { owner = AllowRead group = AllowRead other = AllowRead } chmod(path, mode) let meta = stat(path) assert meta.size == length(contents) assert meta.type == Regular assert meta.mode == mode
lstat : String -> Stat lstat(path)
Returns metadata about the file at path
, but doesn't resolve symbolic
links. If path
is a symbolic link, returns info about the link itself, not
the target path the link refers to. See the Stat
struct for
details on the result.
let path = write_temp("foo") let new_path = Path.join(make_temp_dir(), "new") ln_s(path, new_path) let meta = lstat(new_path) assert meta.type == Symlink
open : (String, OpenMode) -> Handle open(path, mode)
Opens the file at path
in the specified mode
. See OpenMode
for a description of the different modes. Returns a file handle that can be
passed to read()
, write()
, close()
, etc.
In all modes except Append
, the initial file position is 0, meaning reads/
writes will occur at the beginning of the file. In the Append
mode, writes
occur at the end of the file. position()
can be used to modify
the position to read/write at.
let h = open(write_temp("hey\nthere"), Read) ensure close(h) after assert read(h, All) == "hey\nthere"
close : Handle -> () close(handle)
Closes the file handle handle
that was opened previously by a call to
open()
. After this function returns, [handle
] may no longer be
used for any operations. If it is used, a ClosedHandle
exception will be raised.
let path = write_temp("") let h = open(path, Write) ensure close(h) after write(h, "hello") assert read_path(path) == "hello"
read : (Handle, ReadAmount) -> String read(handle, amount)
Reads characters from the file given by handle
in the amount amount
. See
the ReadAmount
struct for details on how to specify an
amount.
If you try to read from the end of a file, raises EndOfFile
.
let h = open(write_temp("hey\nthere"), Read) ensure close(h) after assert read(h, Line) == "hey\n" assert read(h, Chars(2)) == "th" assert read(h, All) == "ere"
write : (Handle, String) -> () write(handle, contents)
Writes contents
to the file given by handle
.
let path = write_temp("hey\nthere") let h = open(path, Write) // File should be truncated. assert read_path(path) == "" ensure close(h) after write(h, "hello\n") write(h, "foo") write(h, "end") assert read_path(path) == "hello\nfooend"
seek : (Handle, Int) -> () seek(handle, pos)
Changes the file position of handle
to pos
, where 0 is the beginning of
the file, and n
is the n
bytes after the beginning. The next read or
write will occur at position pos
.
let path = write_temp("hey\nthere") let h = open(path, ReadWrite) ensure close(h) after seek(h, 4) write(h, "where") assert read_path(path) == "hey\nwhere"
seek_end : Handle -> Int seek_end(handle)
Changes the file position of handle
to the last position. This is useful
for writing at the end of the file or getting the size of the file with
tell()
.
let contents = "hey\nthere" let path = write_temp(contents) let h = open(path, ReadWrite) ensure close(h) after let end = seek_end(h) assert end == length(contents) assert tell(h) == end write(h, "where") assert read_path(path) == "hey\ntherewhere"
tell : Handle -> Int tell(handle)
Returns the file position of handle
, where 0 is the beginning of the file
and n
is the n
bytes after the beginning.
let h = open(write_temp("hey\nthere"), ReadWrite) ensure close(h) after assert tell(h) == 0 assert read(h, Line) == "hey\n" assert tell(h) == 4 write(h, "foo") assert tell(h) == 7 seek(h, 2) assert tell(h) == 2 assert read(h, All) == "y\nfoore"
truncate : Handle -> () truncate(handle)
Truncates the file given by handle
, removing all data from the current
file position up to the end of the file.
let path = write_temp("hey\nthere") let h = open(path, ReadWrite) ensure close(h) after seek(h, 4) truncate(h) assert read_path(path) == "hey\n"
cwd : () -> String cwd()
Returns the current working directory, which starts as the directory in which
par
is initially run.
// Prints the current working directory. print(cwd())
cd : String -> () cd(path)
Changes the current working directory to path
.
// Make foo the new working directory. cd("foo")
sys_temp_dir : String sys_temp_dir
The system's temporary directory. Use make_temp_dir()
to
make a new temporary directory within this directory, and
write_temp()
to write a temporary file into this directory.
// Write to temporary file foo in system temp directory. let path = Path.join(sys_temp_dir, "foo") write_path(path, "bar")
make_temp_dir : () -> String make_temp_dir()
Makes a new temporary directory within sys_temp_dir
,
returning its path. See write_temp()
if you want to write to
a temporary file.
let path = make_temp_dir() assert Path.dir(path) == sys_temp_dir assert ls(path) == []
write_temp : String -> String write_temp(contents)
Writes contents
to a temporary file located within
sys_temp_dir
, returning its path. See
make_temp_dir()
if you want to create a new temporary
directory.
let path = write_temp("foo") assert Path.dir(path) == sys_temp_dir assert read_path(path) == "foo"
ln : (String, String) -> () ln(existing, new)
Creates a hard link at path new
that mirrors the file at path existing
.
A hard link is an alias that refers to the same underlying file (i.e. inode
in linux). If existing
is deleted or moved, new
will still exist with its
contents. If existing
or new
is modified, the other will also be
modified, as the same underlying file is changed. On many systems, hard links
to directories are not allowed.
let path = write_temp("foo") let new_path = Path.join(make_temp_dir(), "new") ln(path, new_path) assert read_path(new_path) == "foo" // Hard link should be maintained even when original is deleted. rm(path) assert read_path(new_path) == "foo"
ln_s : (String, String) -> () ln_s(existing, new)
Creates a symbolic link at path new
that points to path existing
.
A symbolic link is a special file whose contents are a filesystem path; in
this way, it's just a pointer to existing
. If existing
is deleted or
moved, new
will refer to a non-existent path. If existing
is modified,
new
will still point to existing
, and hence you can see the changes.
Symbolic links can refer to directories.
let path = write_temp("foo") let new_path = Path.join(make_temp_dir(), "new") ln_s(path, new_path) assert lstat(new_path).type == Symlink assert stat(new_path).type == Regular assert read_path(new_path) == "foo"
readlink : String -> String readlink(path)
Resolves the symbolic link at path
, returning the target path to which it
refers to.
let path = write_temp("") let new_path = Path.join(make_temp_dir(), "new") ln_s(path, new_path) assert readlink(new_path) == path
chmod : (String, Mode) -> () chmod(path, mode)
Changes the access controls for the file at the given path
to mode
. See
the Mode
struct for details on what can be modified.
On Windows, only the owner
permissions can be changed. For regular
files, the supported values are AllowRead
and
AllowReadWrite
. For directories, only
AllowReadWrite
is supported. If you specify an unsupported
value, raises InvalidWindowsPermissions
.
let path = write_temp("") let new_mode = Mode { owner = AllowReadWrite group = AllowExec other = AllowNone } chmod(path, new_mode) if OS.windows? then assert stat(path).mode.owner == AllowReadWrite else assert stat(path).mode == new_mode
chown : (String, Int) -> () chown(path, uid)
Changes the owner of path
to the user given by ID uid
. This can only be
run by a super-user on UNIX systems. On Windows, raises
NotPermitted
.
// Change owner of "/foo" to the user with ID 0 (generally root). chown("/foo", 0)
chgrp : (String, Int) -> () chgrp(path, gid)
Changes the group of path
to the group given by ID gid
. This can only
be run by the owner of the file or a super-user on UNIX systems. On Windows,
raises NotPermitted
.
// Change group of "foo/bar" to the group with ID 30. chgrp("foo/bar", 30)
Types
struct Stat
Contains metadata about a file. Returned by stat()
.
size
— The file's size.type
— The file type (file, driectory, symlink, etc.); seeFileType
.atime
— The last Unix time the file was accessed, represented as the number of seconds since the epoch.mtime
— The last Unix time the file was modified, represented as the number of seconds since the epoch.mode
— The mode of the file, containing permissions; seeMode
.uid
— The user ID of the file's owner.gid
— The group ID of the file's group.
struct Stat { size : Int type : FileType atime : Int mtime : Int mode : Mode uid : Int gid : Int }
enum FileType
Specifies the type of a file. Returned by stat()
as part of the
Stat
struct.
Regular
— A regular file.Directory
— A directory.Symlink
— A symbolic link.Device
— A device (e.g./dev/null
is the null device).Other
— Some other file (e.g. named pipe, unix socket, etc.).
enum FileType { Regular Directory Symlink Device Other }
struct Mode
Contains access controls for a file. Returned by stat()
as part of
the Stat
struct, and can be changed via chmod()
.
owner
, group
, and other
are the permissions granted to the respective
groups. See Permissions
for values that owner
, group
,
and other
can take on.
On Windows, only owner
permissions are relevant, and the only possible
values are AllowRead
and AllowReadWrite
.
The values for group
and other
will always be the same as owner
.
struct Mode { owner : Permissions group : Permissions other : Permissions }
enum Permissions
Specifies permissions when accessing a file.
AllowNone
— No operations are allowed.AllowRead
— Reading is permitted.AllowWrite
— Writing is permitted.AllowExec
— Executing is permitted.AllowReadWrite
— Reading and writing are permitted.AllowWriteExec
— Writing and executing are permitted.AllowAll
— Reading, writing, and executing are permitted.
enum Permissions { AllowNone AllowRead AllowWrite AllowExec AllowReadWrite AllowReadExec AllowWriteExec AllowAll }
enum OpenMode
Specifies what mode to open a file in. Passed to open()
.
Read
— Open a file for reading.Write
— Open a file for writing. The file is truncated (i.e. all current contents are erased). If the file doesn't exist, it is created.Append
— Open a file for appending. If the file doesn't exist, it is created. All writes occur at the end of the file.ReadWrite
— Open a file for reading and writing. If the file doesn't exist, it is created.Exclusive
— Create and open a file for writing. If the file already exists, raisesExists
.
enum OpenMode { Read Write Append ReadWrite Exclusive }
enum Handle
Represents an open file handle returned by open()
.
enum ReadAmount
Specifies the amount to read from a file.
Chars(n)
— Readn
characters.Line
— Read one line.All
— Read all remaining contents.
enum ReadAmount { Chars(Int) Line All }
Exceptions
exception Exists
The file already exists. Raised if, for instance, mkdir()
is
called with an existing path.
exception DoesntExist
No such file or directory exists. Raised if, for instance, you
stat()
a non-existent path.
exception EndOfFile
Raised by read()
if you attempt to read at the end of a file.
exception PermissionDenied
There aren't sufficient permissions to access a file.
exception NotPermitted
exception ClosedHandle
The file handle has been closed already.
exception BadHandle
A resource is temporarily unavailable; try again.
exception Busy
A resource is busy and can't be used.
exception DiskQuotaExceeded
The disk quota has been exceeded.
exception BadAddress
Bad address in a system call argument.
exception TooLarge
The file is too large.
exception Interrupted
A system call was interrupted.
exception InvalidArgument
An invalid file was given as an argument; for instance, a non-symlink was
passed to readlink()
.
exception IOError
Generic IO error. On Windows, this is raised in place of
NotDirectory
.
exception IllegalDirOperation
There was an illegal operation on a directory. Raised if, for instance,
cp()
is called on a directory.
exception TooManyOpen
There are too many open files.
exception TooManyLinks
There are too many links.
exception SymlinkLoop
There are too many levels of symbolic links to traverse.
exception NameTooLong
A file's name is too long.
exception TableOverflow
The file table has overflowed.
exception NoDevice
No such device exists.
exception OutOfMemory
There isn't enough memory.
exception NoSpace
No space is left on the device.
exception NotBlockDevice
A block device is required.
exception NotDirectory
exception NotSupported
An operation is not supported.
exception NoDeviceOrAddress
No such device or address.
exception BrokenPipe
A pipe was broken. Occurs when you're trying to write to a pipe, but nothing is reading from that pipe.
exception ReadOnlyFS
The filesystem is read-only.
exception InvalidSeek
A seek operation was performed on an invalid file type.
exception NoProcess
No such process.
exception StaleHandle
The file handle is stale.
exception CrossDomainLink
You're trying to perform an operation across two separate filesystems.
exception SystemLimit
A system limit was reached.
exception InvalidWindowsPermissions(Permissions)
For regular files on Windows, AllowRead
and
AllowReadWrite
are the only supported permissions. For
directories on Windows, only AllowReadWrite
is supported.
exception UnknownError(String)
An unknown error, where the argument is the error code.